From ed6277cf2522ae9f29ee944962ac0d7e5c36047b Mon Sep 17 00:00:00 2001 From: Paula Stachova Date: Thu, 16 Jan 2025 12:25:42 +0100 Subject: [PATCH 1/8] feat: add SchemaAccessor COMPASS-8799 --- package-lock.json | 16 ++++++++------ package.json | 1 + src/index.ts | 45 ++++++++++++++++--------------------- src/schema-accessor.ts | 48 ++++++++++++++++++++++++++++++++++++++++ src/schema-analyzer.ts | 1 + src/schema-convertors.ts | 29 ++++++++++++++++++++++++ src/types.ts | 22 ++++++++++++++++++ src/utils.ts | 27 ++++++++++++++++++++++ 8 files changed, 156 insertions(+), 33 deletions(-) create mode 100644 src/schema-accessor.ts create mode 100644 src/schema-convertors.ts create mode 100644 src/types.ts create mode 100644 src/utils.ts diff --git a/package-lock.json b/package-lock.json index 06c945e..fa08e8e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "mongodb-schema": "bin/mongodb-schema" }, "devDependencies": { + "@types/json-schema": "^7.0.15", "@types/mocha": "^10.0.1", "@types/node": "^18.11.18", "@types/reservoir": "^0.1.0", @@ -2284,10 +2285,11 @@ "dev": true }, "node_modules/@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", - "dev": true + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" }, "node_modules/@types/json5": { "version": "0.0.29", @@ -9825,9 +9827,9 @@ "dev": true }, "@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, "@types/json5": { diff --git a/package.json b/package.json index 0097cff..b6382a7 100644 --- a/package.json +++ b/package.json @@ -56,6 +56,7 @@ "@types/mocha": "^10.0.1", "@types/node": "^18.11.18", "@types/reservoir": "^0.1.0", + "@types/json-schema": "^7.0.15", "@typescript-eslint/eslint-plugin": "^5.47.1", "@typescript-eslint/parser": "^5.47.1", "bson": "^6.7.0", diff --git a/src/index.ts b/src/index.ts index b2f4a5f..cc13e01 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,4 @@ +import { InternalSchemaBasedAccessor, SchemaAccessor } from './schema-accessor'; import { SchemaAnalyzer } from './schema-analyzer'; import type { ArraySchemaType, @@ -6,7 +7,7 @@ import type { DocumentSchemaType, PrimitiveSchemaType, SchemaType, - Schema, + Schema as InternalSchema, SchemaField, SchemaParseOptions, SimplifiedSchemaBaseType, @@ -17,31 +18,18 @@ import type { SimplifiedSchema } from './schema-analyzer'; import * as schemaStats from './stats'; +import { AnyIterable, StandardJSONSchema, MongodbJSONSchema, ExtendedJSONSchema } from './types'; +import { getCompletedSchemaAnalyzer } from './utils'; -type AnyIterable = Iterable | AsyncIterable; - -function verifyStreamSource( - source: AnyIterable -): AnyIterable { - if (!(Symbol.iterator in source) && !(Symbol.asyncIterator in source)) { - throw new Error( - 'Unknown input type for `docs`. Must be an array, ' + - 'stream or MongoDB Cursor.' - ); - } - - return source; -} - -async function getCompletedSchemaAnalyzer( +/** + * Analyze documents - schema can be retrieved in different formats. + */ +async function analyzeDocuments( source: AnyIterable, options?: SchemaParseOptions -): Promise { - const analyzer = new SchemaAnalyzer(options); - for await (const doc of verifyStreamSource(source)) { - analyzer.analyzeDoc(doc); - } - return analyzer; +): Promise { + const internalSchema = (await getCompletedSchemaAnalyzer(source, options)).getResult(); + return new InternalSchemaBasedAccessor(internalSchema, options?.signal); } /** @@ -51,7 +39,7 @@ async function getCompletedSchemaAnalyzer( async function parseSchema( source: AnyIterable, options?: SchemaParseOptions -): Promise { +): Promise { return (await getCompletedSchemaAnalyzer(source, options)).getResult(); } @@ -78,7 +66,8 @@ export type { DocumentSchemaType, PrimitiveSchemaType, SchemaType, - Schema, + InternalSchema as Schema, + InternalSchema, SchemaField, SchemaParseOptions, SimplifiedSchemaBaseType, @@ -86,11 +75,15 @@ export type { SimplifiedSchemaDocumentType, SimplifiedSchemaType, SimplifiedSchemaField, - SimplifiedSchema + SimplifiedSchema, + StandardJSONSchema, + MongodbJSONSchema, + ExtendedJSONSchema }; export { parseSchema, + analyzeDocuments, getSchemaPaths, getSimplifiedSchema, SchemaAnalyzer, diff --git a/src/schema-accessor.ts b/src/schema-accessor.ts new file mode 100644 index 0000000..ff6f092 --- /dev/null +++ b/src/schema-accessor.ts @@ -0,0 +1,48 @@ +import { Schema as InternalSchema } from './schema-analyzer'; +import { internalSchemaToExtended, internalSchemaToMongodb, internalSchemaToStandard } from './schema-convertors'; +import { ExtendedJSONSchema, MongodbJSONSchema, StandardJSONSchema } from './types'; + +export interface SchemaAccessor { + getStandardJsonSchema: () => Promise; + getMongodbJsonSchema: () => Promise; + getExtendedJsonSchema: () => Promise; + getInternalSchema: () => Promise; +} + +/** + * Accessor for different schema formats. + * Internal schema is provided at initialization, + * the others are converted lazily and memoized. + * Conversion can be aborted. + */ +export class InternalSchemaBasedAccessor implements SchemaAccessor { + private internalSchema: InternalSchema; + private standardJSONSchema?: StandardJSONSchema; + private mongodbJSONSchema?: MongodbJSONSchema; + private extendedJSONSchema?: ExtendedJSONSchema; + private signal?: AbortSignal; + + constructor(internalSchema: InternalSchema, signal?: AbortSignal) { + this.signal = signal; + this.internalSchema = internalSchema; + } + + async getInternalSchema(): Promise { + return this.internalSchema; + } + + async getStandardJsonSchema(): Promise { + if (this.standardJSONSchema) return this.standardJSONSchema; + return this.standardJSONSchema = await internalSchemaToStandard(this.internalSchema, { signal: this.signal }); + } + + async getMongodbJsonSchema(): Promise { + if (this.mongodbJSONSchema) return this.mongodbJSONSchema; + return this.mongodbJSONSchema = await internalSchemaToMongodb(this.internalSchema, { signal: this.signal }); + } + + async getExtendedJsonSchema(): Promise { + if (this.extendedJSONSchema) return this.extendedJSONSchema; + return this.extendedJSONSchema = await internalSchemaToExtended(this.internalSchema, { signal: this.signal }); + } +} diff --git a/src/schema-analyzer.ts b/src/schema-analyzer.ts index 29817bf..26a28d4 100644 --- a/src/schema-analyzer.ts +++ b/src/schema-analyzer.ts @@ -163,6 +163,7 @@ type SemanticTypeMap = { export type SchemaParseOptions = { semanticTypes?: boolean | SemanticTypeMap; storeValues?: boolean; + signal?: AbortSignal; }; /** diff --git a/src/schema-convertors.ts b/src/schema-convertors.ts new file mode 100644 index 0000000..a4762ff --- /dev/null +++ b/src/schema-convertors.ts @@ -0,0 +1,29 @@ +import { Schema as InternalSchema } from './schema-analyzer'; +import { ExtendedJSONSchema, MongodbJSONSchema, StandardJSONSchema } from './types'; + +export function internalSchemaToStandard( + internalSchema: InternalSchema, + options: { + signal?: AbortSignal +}): StandardJSONSchema { + // TODO: COMPASS-8700 + return {}; +} + +export function internalSchemaToMongodb( + internalSchema: InternalSchema, + options: { + signal?: AbortSignal +}): MongodbJSONSchema { + // TODO: COMPASS-8701 + return {} as MongodbJSONSchema; +} + +export function internalSchemaToExtended( + internalSchema: InternalSchema, + options: { + signal?: AbortSignal +}): ExtendedJSONSchema { + // TODO: COMPASS-8702 + return {} as ExtendedJSONSchema; +} diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..1ecd17f --- /dev/null +++ b/src/types.ts @@ -0,0 +1,22 @@ +import { JSONSchema4 } from 'json-schema'; + +export type StandardJSONSchema = JSONSchema4; + +export type MongodbJSONSchema = Pick & { + bsonType: string; + properties?: Record; + items?: MongodbJSONSchema[]; + anyOf?: MongodbJSONSchema[]; +} + +export type ExtendedJSONSchema = StandardJSONSchema & { + ['x-bsonType']: string; + ['x-metadata']: { + hasDuplicates: boolean; + probability: number; + count: number; + }; + ['x-sampleValues']: any[]; +} + +export type AnyIterable = Iterable | AsyncIterable; diff --git a/src/utils.ts b/src/utils.ts new file mode 100644 index 0000000..ee51f33 --- /dev/null +++ b/src/utils.ts @@ -0,0 +1,27 @@ +import { SchemaAnalyzer, SchemaParseOptions } from './schema-analyzer'; +import { AnyIterable } from './types'; + +export function verifyStreamSource( + source: AnyIterable +): AnyIterable { + if (!(Symbol.iterator in source) && !(Symbol.asyncIterator in source)) { + throw new Error( + 'Unknown input type for `docs`. Must be an array, ' + + 'stream or MongoDB Cursor.' + ); + } + + return source; +} + +export async function getCompletedSchemaAnalyzer( + source: AnyIterable, + options?: SchemaParseOptions +): Promise { + const analyzer = new SchemaAnalyzer(options); + for await (const doc of verifyStreamSource(source)) { + if (options?.signal?.aborted) throw options.signal.aborted; + analyzer.analyzeDoc(doc); + } + return analyzer; +} From 686d7c468020b25d95605dcd971452f20cf37a30 Mon Sep 17 00:00:00 2001 From: Paula Stachova Date: Thu, 16 Jan 2025 13:04:25 +0100 Subject: [PATCH 2/8] depcheck ignore json-schema (only using types) --- .depcheckrc | 1 + src/types.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.depcheckrc b/.depcheckrc index 2d575ec..2d129a8 100644 --- a/.depcheckrc +++ b/.depcheckrc @@ -1,3 +1,4 @@ ignores: - 'reservoir' - '@types/reservoir' + - 'json-schema' diff --git a/src/types.ts b/src/types.ts index 1ecd17f..c31603f 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,4 +1,4 @@ -import { JSONSchema4 } from 'json-schema'; +import { type JSONSchema4 } from 'json-schema'; export type StandardJSONSchema = JSONSchema4; From 1249f8b30cacdc89508f70d51f588e864469eee2 Mon Sep 17 00:00:00 2001 From: Paula Stachova Date: Thu, 16 Jan 2025 16:19:01 +0100 Subject: [PATCH 3/8] add tests --- package-lock.json | 284 +++++++++++++++++++++++++++++++++ package.json | 4 +- src/schema-accessor.ts | 8 +- src/schema-convertors.ts | 12 +- test/analyze-documents.test.ts | 25 +++ 5 files changed, 325 insertions(+), 8 deletions(-) create mode 100644 test/analyze-documents.test.ts diff --git a/package-lock.json b/package-lock.json index fa08e8e..31ab965 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,7 @@ "@types/mocha": "^10.0.1", "@types/node": "^18.11.18", "@types/reservoir": "^0.1.0", + "@types/sinon": "^17.0.3", "@typescript-eslint/eslint-plugin": "^5.47.1", "@typescript-eslint/parser": "^5.47.1", "bson": "^6.7.0", @@ -35,6 +36,7 @@ "mocha": "^10.2.0", "mongodb": "^6.6.1", "nyc": "^15.1.0", + "sinon": "^19.0.2", "ts-node": "^10.9.1", "typescript": "^4.9.4" }, @@ -1363,6 +1365,55 @@ "node": ">= 8" } }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "13.0.5", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-13.0.5.tgz", + "integrity": "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.1" + } + }, + "node_modules/@sinonjs/samsam": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.2.tgz", + "integrity": "sha512-v46t/fwnhejRSFTGqbpn9u+LQ9xJDse10gNnPgAcxgdoCDMXj/G2asWAC/8Qs+BAZDicX+MNZouXT1A7c83kVw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.1", + "lodash.get": "^4.4.2", + "type-detect": "^4.1.0" + } + }, + "node_modules/@sinonjs/samsam/node_modules/type-detect": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", + "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/@sinonjs/text-encoding": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.3.tgz", + "integrity": "sha512-DE427ROAphMQzU4ENbliGYrBSYPXF+TtLg9S8vzeA+OF4ZKzoDdzfL8sxuMUGS/lgRhM6j1URSk9ghf7Xo1tyA==", + "dev": true, + "license": "(Unlicense OR Apache-2.0)" + }, "node_modules/@smithy/abort-controller": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-1.0.1.tgz", @@ -2333,6 +2384,23 @@ "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", "dev": true }, + "node_modules/@types/sinon": { + "version": "17.0.3", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-17.0.3.tgz", + "integrity": "sha512-j3uovdn8ewky9kRBG19bOwaZbexJu/XjtkHyjvUgt4xfPFz18dcORIMqnYh66Fx3Powhcr85NT5+er3+oViapw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/sinonjs__fake-timers": "*" + } + }, + "node_modules/@types/sinonjs__fake-timers": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.5.tgz", + "integrity": "sha512-mQkU2jY8jJEF7YHjHvsQO8+3ughTL1mcnn96igfhONmR+fUPSKIkefQYpSe8bsly2Ep7oQbn/6VG5/9/0qcArQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/webidl-conversions": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", @@ -5421,6 +5489,13 @@ "node": ">=0.6.0" } }, + "node_modules/just-extend": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-6.2.0.tgz", + "integrity": "sha512-cYofQu2Xpom82S6qD778jBDpwvvy39s1l/hrYij2u9AMdQcGRpaBu6kY4mVhuno5kJVi1DAz4aiphA2WI1/OAw==", + "dev": true, + "license": "MIT" + }, "node_modules/lcov-parse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-1.0.0.tgz", @@ -5473,6 +5548,13 @@ "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", "dev": true }, + "node_modules/lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -5996,6 +6078,20 @@ "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", "dev": true }, + "node_modules/nise": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/nise/-/nise-6.1.1.tgz", + "integrity": "sha512-aMSAzLVY7LyeM60gvBS423nBmIPP+Wy7St7hsb+8/fc1HmeoHJfLO8CKse4u3BtOZvQLJghYPI2i/1WZrEj5/g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.1", + "@sinonjs/fake-timers": "^13.0.1", + "@sinonjs/text-encoding": "^0.7.3", + "just-extend": "^6.2.0", + "path-to-regexp": "^8.1.0" + } + }, "node_modules/node-preload": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", @@ -6403,6 +6499,16 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "node_modules/path-to-regexp": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz", + "integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + } + }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -6911,6 +7017,48 @@ "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true }, + "node_modules/sinon": { + "version": "19.0.2", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-19.0.2.tgz", + "integrity": "sha512-euuToqM+PjO4UgXeLETsfQiuoyPXlqFezr6YZDFwHR3t4qaX0fZUe1MfPMznTL5f8BWrVS89KduLdMUsxFCO6g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.1", + "@sinonjs/fake-timers": "^13.0.2", + "@sinonjs/samsam": "^8.0.1", + "diff": "^7.0.0", + "nise": "^6.1.1", + "supports-color": "^7.2.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/sinon" + } + }, + "node_modules/sinon/node_modules/diff": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz", + "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/sinon/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -7345,6 +7493,16 @@ "node": ">= 0.8.0" } }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/type-fest": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", @@ -8933,6 +9091,49 @@ "fastq": "^1.6.0" } }, + "@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/fake-timers": { + "version": "13.0.5", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-13.0.5.tgz", + "integrity": "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==", + "dev": true, + "requires": { + "@sinonjs/commons": "^3.0.1" + } + }, + "@sinonjs/samsam": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.2.tgz", + "integrity": "sha512-v46t/fwnhejRSFTGqbpn9u+LQ9xJDse10gNnPgAcxgdoCDMXj/G2asWAC/8Qs+BAZDicX+MNZouXT1A7c83kVw==", + "dev": true, + "requires": { + "@sinonjs/commons": "^3.0.1", + "lodash.get": "^4.4.2", + "type-detect": "^4.1.0" + }, + "dependencies": { + "type-detect": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", + "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", + "dev": true + } + } + }, + "@sinonjs/text-encoding": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.3.tgz", + "integrity": "sha512-DE427ROAphMQzU4ENbliGYrBSYPXF+TtLg9S8vzeA+OF4ZKzoDdzfL8sxuMUGS/lgRhM6j1URSk9ghf7Xo1tyA==", + "dev": true + }, "@smithy/abort-controller": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-1.0.1.tgz", @@ -9874,6 +10075,21 @@ "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", "dev": true }, + "@types/sinon": { + "version": "17.0.3", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-17.0.3.tgz", + "integrity": "sha512-j3uovdn8ewky9kRBG19bOwaZbexJu/XjtkHyjvUgt4xfPFz18dcORIMqnYh66Fx3Powhcr85NT5+er3+oViapw==", + "dev": true, + "requires": { + "@types/sinonjs__fake-timers": "*" + } + }, + "@types/sinonjs__fake-timers": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.5.tgz", + "integrity": "sha512-mQkU2jY8jJEF7YHjHvsQO8+3ughTL1mcnn96igfhONmR+fUPSKIkefQYpSe8bsly2Ep7oQbn/6VG5/9/0qcArQ==", + "dev": true + }, "@types/webidl-conversions": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", @@ -12150,6 +12366,12 @@ "verror": "1.10.0" } }, + "just-extend": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-6.2.0.tgz", + "integrity": "sha512-cYofQu2Xpom82S6qD778jBDpwvvy39s1l/hrYij2u9AMdQcGRpaBu6kY4mVhuno5kJVi1DAz4aiphA2WI1/OAw==", + "dev": true + }, "lcov-parse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-1.0.0.tgz", @@ -12193,6 +12415,12 @@ "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", "dev": true }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", + "dev": true + }, "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -12559,6 +12787,19 @@ "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", "dev": true }, + "nise": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/nise/-/nise-6.1.1.tgz", + "integrity": "sha512-aMSAzLVY7LyeM60gvBS423nBmIPP+Wy7St7hsb+8/fc1HmeoHJfLO8CKse4u3BtOZvQLJghYPI2i/1WZrEj5/g==", + "dev": true, + "requires": { + "@sinonjs/commons": "^3.0.1", + "@sinonjs/fake-timers": "^13.0.1", + "@sinonjs/text-encoding": "^0.7.3", + "just-extend": "^6.2.0", + "path-to-regexp": "^8.1.0" + } + }, "node-preload": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", @@ -12871,6 +13112,12 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "path-to-regexp": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz", + "integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==", + "dev": true + }, "path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -13231,6 +13478,37 @@ "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true }, + "sinon": { + "version": "19.0.2", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-19.0.2.tgz", + "integrity": "sha512-euuToqM+PjO4UgXeLETsfQiuoyPXlqFezr6YZDFwHR3t4qaX0fZUe1MfPMznTL5f8BWrVS89KduLdMUsxFCO6g==", + "dev": true, + "requires": { + "@sinonjs/commons": "^3.0.1", + "@sinonjs/fake-timers": "^13.0.2", + "@sinonjs/samsam": "^8.0.1", + "diff": "^7.0.0", + "nise": "^6.1.1", + "supports-color": "^7.2.0" + }, + "dependencies": { + "diff": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz", + "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -13556,6 +13834,12 @@ "prelude-ls": "^1.2.1" } }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, "type-fest": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", diff --git a/package.json b/package.json index b6382a7..d7967fc 100644 --- a/package.json +++ b/package.json @@ -53,10 +53,11 @@ "reservoir": "^0.1.2" }, "devDependencies": { + "@types/json-schema": "^7.0.15", "@types/mocha": "^10.0.1", "@types/node": "^18.11.18", "@types/reservoir": "^0.1.0", - "@types/json-schema": "^7.0.15", + "@types/sinon": "^17.0.3", "@typescript-eslint/eslint-plugin": "^5.47.1", "@typescript-eslint/parser": "^5.47.1", "bson": "^6.7.0", @@ -73,6 +74,7 @@ "mocha": "^10.2.0", "mongodb": "^6.6.1", "nyc": "^15.1.0", + "sinon": "^19.0.2", "ts-node": "^10.9.1", "typescript": "^4.9.4" }, diff --git a/src/schema-accessor.ts b/src/schema-accessor.ts index ff6f092..288dd6c 100644 --- a/src/schema-accessor.ts +++ b/src/schema-accessor.ts @@ -1,5 +1,5 @@ import { Schema as InternalSchema } from './schema-analyzer'; -import { internalSchemaToExtended, internalSchemaToMongodb, internalSchemaToStandard } from './schema-convertors'; +import convertors from './schema-convertors'; import { ExtendedJSONSchema, MongodbJSONSchema, StandardJSONSchema } from './types'; export interface SchemaAccessor { @@ -33,16 +33,16 @@ export class InternalSchemaBasedAccessor implements SchemaAccessor { async getStandardJsonSchema(): Promise { if (this.standardJSONSchema) return this.standardJSONSchema; - return this.standardJSONSchema = await internalSchemaToStandard(this.internalSchema, { signal: this.signal }); + return this.standardJSONSchema = await convertors.internalSchemaToStandard(this.internalSchema, { signal: this.signal }); } async getMongodbJsonSchema(): Promise { if (this.mongodbJSONSchema) return this.mongodbJSONSchema; - return this.mongodbJSONSchema = await internalSchemaToMongodb(this.internalSchema, { signal: this.signal }); + return this.mongodbJSONSchema = await convertors.internalSchemaToMongodb(this.internalSchema, { signal: this.signal }); } async getExtendedJsonSchema(): Promise { if (this.extendedJSONSchema) return this.extendedJSONSchema; - return this.extendedJSONSchema = await internalSchemaToExtended(this.internalSchema, { signal: this.signal }); + return this.extendedJSONSchema = await convertors.internalSchemaToExtended(this.internalSchema, { signal: this.signal }); } } diff --git a/src/schema-convertors.ts b/src/schema-convertors.ts index a4762ff..b8a87f6 100644 --- a/src/schema-convertors.ts +++ b/src/schema-convertors.ts @@ -1,7 +1,7 @@ import { Schema as InternalSchema } from './schema-analyzer'; import { ExtendedJSONSchema, MongodbJSONSchema, StandardJSONSchema } from './types'; -export function internalSchemaToStandard( +function internalSchemaToStandard( internalSchema: InternalSchema, options: { signal?: AbortSignal @@ -10,7 +10,7 @@ export function internalSchemaToStandard( return {}; } -export function internalSchemaToMongodb( +function internalSchemaToMongodb( internalSchema: InternalSchema, options: { signal?: AbortSignal @@ -19,7 +19,7 @@ export function internalSchemaToMongodb( return {} as MongodbJSONSchema; } -export function internalSchemaToExtended( +function internalSchemaToExtended( internalSchema: InternalSchema, options: { signal?: AbortSignal @@ -27,3 +27,9 @@ export function internalSchemaToExtended( // TODO: COMPASS-8702 return {} as ExtendedJSONSchema; } + +export default { + internalSchemaToStandard, + internalSchemaToMongodb, + internalSchemaToExtended +}; diff --git a/test/analyze-documents.test.ts b/test/analyze-documents.test.ts new file mode 100644 index 0000000..3fa8101 --- /dev/null +++ b/test/analyze-documents.test.ts @@ -0,0 +1,25 @@ +import { analyzeDocuments } from '../src'; +import convertors from '../src/schema-convertors'; +import sinon from 'sinon'; +import assert from 'assert'; + +describe('analyzeDocuments', function() { + const docs = [{}]; + + it('Converts lazily', async function() { + const convertSpy = sinon.spy(convertors, 'internalSchemaToStandard'); + const analyzeResults = await analyzeDocuments(docs); + assert.strictEqual(convertSpy.called, false); + await analyzeResults.getStandardJsonSchema(); + assert.strictEqual(convertSpy.calledOnce, true); + }); + + it('Only converts the same format once', async function() { + const convertSpy = sinon.spy(convertors, 'internalSchemaToExtended'); + const analyzeResults = await analyzeDocuments(docs); + await analyzeResults.getExtendedJsonSchema(); + await analyzeResults.getExtendedJsonSchema(); + await analyzeResults.getExtendedJsonSchema(); + assert.strictEqual(convertSpy.calledOnce, true); + }); +}); From 2350b28aaa5693acf15f1568e19a717d97f0621f Mon Sep 17 00:00:00 2001 From: Paula Stachova Date: Mon, 20 Jan 2025 13:13:29 +0100 Subject: [PATCH 4/8] pr suggestions --- src/index.ts | 4 ++-- src/schema-accessor.ts | 28 +++++++++++++++------------- src/schema-analyzer.ts | 26 ++++++++++++++++++++++++++ src/schema-convertors.ts | 10 +++++----- src/utils.ts | 27 --------------------------- 5 files changed, 48 insertions(+), 47 deletions(-) delete mode 100644 src/utils.ts diff --git a/src/index.ts b/src/index.ts index cc13e01..08dd157 100644 --- a/src/index.ts +++ b/src/index.ts @@ -18,7 +18,7 @@ import type { SimplifiedSchema } from './schema-analyzer'; import * as schemaStats from './stats'; -import { AnyIterable, StandardJSONSchema, MongodbJSONSchema, ExtendedJSONSchema } from './types'; +import { AnyIterable, StandardJSONSchema, MongoDBJSONSchema, ExtendedJSONSchema } from './types'; import { getCompletedSchemaAnalyzer } from './utils'; /** @@ -77,7 +77,7 @@ export type { SimplifiedSchemaField, SimplifiedSchema, StandardJSONSchema, - MongodbJSONSchema, + MongoDBJSONSchema, ExtendedJSONSchema }; diff --git a/src/schema-accessor.ts b/src/schema-accessor.ts index 288dd6c..530d8bd 100644 --- a/src/schema-accessor.ts +++ b/src/schema-accessor.ts @@ -1,14 +1,18 @@ import { Schema as InternalSchema } from './schema-analyzer'; import convertors from './schema-convertors'; -import { ExtendedJSONSchema, MongodbJSONSchema, StandardJSONSchema } from './types'; +import { ExtendedJSONSchema, MongoDBJSONSchema, StandardJSONSchema } from './types'; export interface SchemaAccessor { getStandardJsonSchema: () => Promise; - getMongodbJsonSchema: () => Promise; + getMongoDBJsonSchema: () => Promise; getExtendedJsonSchema: () => Promise; getInternalSchema: () => Promise; } +type Options = { + signal?: AbortSignal; +} + /** * Accessor for different schema formats. * Internal schema is provided at initialization, @@ -18,31 +22,29 @@ export interface SchemaAccessor { export class InternalSchemaBasedAccessor implements SchemaAccessor { private internalSchema: InternalSchema; private standardJSONSchema?: StandardJSONSchema; - private mongodbJSONSchema?: MongodbJSONSchema; + private mongodbJSONSchema?: MongoDBJSONSchema; private extendedJSONSchema?: ExtendedJSONSchema; - private signal?: AbortSignal; - constructor(internalSchema: InternalSchema, signal?: AbortSignal) { - this.signal = signal; + constructor(internalSchema: InternalSchema) { this.internalSchema = internalSchema; } - async getInternalSchema(): Promise { + async getInternalSchema(options?: Options): Promise { return this.internalSchema; } - async getStandardJsonSchema(): Promise { + async getStandardJsonSchema(options: Options = {}): Promise { if (this.standardJSONSchema) return this.standardJSONSchema; - return this.standardJSONSchema = await convertors.internalSchemaToStandard(this.internalSchema, { signal: this.signal }); + return this.standardJSONSchema = await convertors.internalSchemaToStandard(this.internalSchema, options); } - async getMongodbJsonSchema(): Promise { + async getMongoDBJsonSchema(options: Options = {}): Promise { if (this.mongodbJSONSchema) return this.mongodbJSONSchema; - return this.mongodbJSONSchema = await convertors.internalSchemaToMongodb(this.internalSchema, { signal: this.signal }); + return this.mongodbJSONSchema = await convertors.internalSchemaToMongoDB(this.internalSchema, options); } - async getExtendedJsonSchema(): Promise { + async getExtendedJsonSchema(options: Options = {}): Promise { if (this.extendedJSONSchema) return this.extendedJSONSchema; - return this.extendedJSONSchema = await convertors.internalSchemaToExtended(this.internalSchema, { signal: this.signal }); + return this.extendedJSONSchema = await convertors.internalSchemaToExtended(this.internalSchema, options); } } diff --git a/src/schema-analyzer.ts b/src/schema-analyzer.ts index 26a28d4..0d41ad4 100644 --- a/src/schema-analyzer.ts +++ b/src/schema-analyzer.ts @@ -17,6 +17,7 @@ import { } from 'bson'; import semanticTypes from './semantic-types'; +import { AnyIterable } from './types'; type TypeCastMap = { Array: unknown[]; @@ -586,3 +587,28 @@ export class SchemaAnalyzer { return simplifiedSchema(this.schemaAnalysisRoot.fields); } } + +export function verifyStreamSource( + source: AnyIterable +): AnyIterable { + if (!(Symbol.iterator in source) && !(Symbol.asyncIterator in source)) { + throw new Error( + 'Unknown input type for `docs`. Must be an array, ' + + 'stream or MongoDB Cursor.' + ); + } + + return source; +} + +export async function getCompletedSchemaAnalyzer( + source: AnyIterable, + options?: SchemaParseOptions +): Promise { + const analyzer = new SchemaAnalyzer(options); + for await (const doc of verifyStreamSource(source)) { + if (options?.signal?.aborted) throw options.signal.aborted; + analyzer.analyzeDoc(doc); + } + return analyzer; +} diff --git a/src/schema-convertors.ts b/src/schema-convertors.ts index b8a87f6..435e991 100644 --- a/src/schema-convertors.ts +++ b/src/schema-convertors.ts @@ -1,5 +1,5 @@ import { Schema as InternalSchema } from './schema-analyzer'; -import { ExtendedJSONSchema, MongodbJSONSchema, StandardJSONSchema } from './types'; +import { ExtendedJSONSchema, MongoDBJSONSchema, StandardJSONSchema } from './types'; function internalSchemaToStandard( internalSchema: InternalSchema, @@ -10,13 +10,13 @@ function internalSchemaToStandard( return {}; } -function internalSchemaToMongodb( +function internalSchemaToMongoDB( internalSchema: InternalSchema, options: { signal?: AbortSignal -}): MongodbJSONSchema { +}): MongoDBJSONSchema { // TODO: COMPASS-8701 - return {} as MongodbJSONSchema; + return {} as MongoDBJSONSchema; } function internalSchemaToExtended( @@ -30,6 +30,6 @@ function internalSchemaToExtended( export default { internalSchemaToStandard, - internalSchemaToMongodb, + internalSchemaToMongoDB, internalSchemaToExtended }; diff --git a/src/utils.ts b/src/utils.ts deleted file mode 100644 index ee51f33..0000000 --- a/src/utils.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { SchemaAnalyzer, SchemaParseOptions } from './schema-analyzer'; -import { AnyIterable } from './types'; - -export function verifyStreamSource( - source: AnyIterable -): AnyIterable { - if (!(Symbol.iterator in source) && !(Symbol.asyncIterator in source)) { - throw new Error( - 'Unknown input type for `docs`. Must be an array, ' + - 'stream or MongoDB Cursor.' - ); - } - - return source; -} - -export async function getCompletedSchemaAnalyzer( - source: AnyIterable, - options?: SchemaParseOptions -): Promise { - const analyzer = new SchemaAnalyzer(options); - for await (const doc of verifyStreamSource(source)) { - if (options?.signal?.aborted) throw options.signal.aborted; - analyzer.analyzeDoc(doc); - } - return analyzer; -} From f25238d7cb35d55d3b4f93b7f6fda5131ef7d163 Mon Sep 17 00:00:00 2001 From: Paula Stachova Date: Mon, 20 Jan 2025 13:16:14 +0100 Subject: [PATCH 5/8] update types --- src/types.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/types.ts b/src/types.ts index c31603f..2b6c0c3 100644 --- a/src/types.ts +++ b/src/types.ts @@ -2,11 +2,11 @@ import { type JSONSchema4 } from 'json-schema'; export type StandardJSONSchema = JSONSchema4; -export type MongodbJSONSchema = Pick & { - bsonType: string; - properties?: Record; - items?: MongodbJSONSchema[]; - anyOf?: MongodbJSONSchema[]; +export type MongoDBJSONSchema = Pick & { + bsonType?: string | string[]; + properties?: Record; + items?: MongoDBJSONSchema | MongoDBJSONSchema[]; + anyOf?: MongoDBJSONSchema[]; } export type ExtendedJSONSchema = StandardJSONSchema & { From 6c7d147d2fa001373272edbca5650ebf8c089450 Mon Sep 17 00:00:00 2001 From: Paula Stachova Date: Mon, 20 Jan 2025 13:19:58 +0100 Subject: [PATCH 6/8] . --- src/index.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/index.ts b/src/index.ts index 08dd157..3dfc6ed 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,5 @@ import { InternalSchemaBasedAccessor, SchemaAccessor } from './schema-accessor'; -import { SchemaAnalyzer } from './schema-analyzer'; +import { getCompletedSchemaAnalyzer, SchemaAnalyzer } from './schema-analyzer'; import type { ArraySchemaType, BaseSchemaType, @@ -19,7 +19,6 @@ import type { } from './schema-analyzer'; import * as schemaStats from './stats'; import { AnyIterable, StandardJSONSchema, MongoDBJSONSchema, ExtendedJSONSchema } from './types'; -import { getCompletedSchemaAnalyzer } from './utils'; /** * Analyze documents - schema can be retrieved in different formats. @@ -29,7 +28,7 @@ async function analyzeDocuments( options?: SchemaParseOptions ): Promise { const internalSchema = (await getCompletedSchemaAnalyzer(source, options)).getResult(); - return new InternalSchemaBasedAccessor(internalSchema, options?.signal); + return new InternalSchemaBasedAccessor(internalSchema); } /** From 2b08856cbdb2fe9eaeb97091dab1964bc6d3beb4 Mon Sep 17 00:00:00 2001 From: Paula Stachova Date: Tue, 21 Jan 2025 16:35:13 +0100 Subject: [PATCH 7/8] Update src/schema-analyzer.ts Co-authored-by: Anna Henningsen --- src/schema-analyzer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/schema-analyzer.ts b/src/schema-analyzer.ts index 0d41ad4..4f00040 100644 --- a/src/schema-analyzer.ts +++ b/src/schema-analyzer.ts @@ -607,7 +607,7 @@ export async function getCompletedSchemaAnalyzer( ): Promise { const analyzer = new SchemaAnalyzer(options); for await (const doc of verifyStreamSource(source)) { - if (options?.signal?.aborted) throw options.signal.aborted; + if (options?.signal?.aborted) throw options.signal.reason; analyzer.analyzeDoc(doc); } return analyzer; From 2df3d33e3e5088a001e1a934a4b3ff2321a66168 Mon Sep 17 00:00:00 2001 From: Paula Stachova Date: Tue, 21 Jan 2025 17:09:59 +0100 Subject: [PATCH 8/8] bump node types and use ??= --- package-lock.json | 38 +++++++++++++++++++++++++++++--------- package.json | 2 +- src/schema-accessor.ts | 9 +++------ 3 files changed, 33 insertions(+), 16 deletions(-) diff --git a/package-lock.json b/package-lock.json index 31ab965..5f9e9cd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,7 +17,7 @@ "devDependencies": { "@types/json-schema": "^7.0.15", "@types/mocha": "^10.0.1", - "@types/node": "^18.11.18", + "@types/node": "^22.10.7", "@types/reservoir": "^0.1.0", "@types/sinon": "^17.0.3", "@typescript-eslint/eslint-plugin": "^5.47.1", @@ -2361,10 +2361,14 @@ "dev": true }, "node_modules/@types/node": { - "version": "18.11.18", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz", - "integrity": "sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==", - "dev": true + "version": "22.10.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.7.tgz", + "integrity": "sha512-V09KvXxFiutGp6B7XkpaDXlNadZxrzajcY50EuoLIpQ6WWYCSvf19lVIazzfIzQvhUN2HjX12spLojTnhuKlGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.20.0" + } }, "node_modules/@types/parse-json": { "version": "4.0.0", @@ -7549,6 +7553,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "dev": true, + "license": "MIT" + }, "node_modules/uri-js": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", @@ -10052,10 +10063,13 @@ "dev": true }, "@types/node": { - "version": "18.11.18", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz", - "integrity": "sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==", - "dev": true + "version": "22.10.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.7.tgz", + "integrity": "sha512-V09KvXxFiutGp6B7XkpaDXlNadZxrzajcY50EuoLIpQ6WWYCSvf19lVIazzfIzQvhUN2HjX12spLojTnhuKlGg==", + "dev": true, + "requires": { + "undici-types": "~6.20.0" + } }, "@types/parse-json": { "version": "4.0.0", @@ -13873,6 +13887,12 @@ "which-boxed-primitive": "^1.0.2" } }, + "undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "dev": true + }, "uri-js": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", diff --git a/package.json b/package.json index d7967fc..aa169a0 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ "devDependencies": { "@types/json-schema": "^7.0.15", "@types/mocha": "^10.0.1", - "@types/node": "^18.11.18", + "@types/node": "^22.10.7", "@types/reservoir": "^0.1.0", "@types/sinon": "^17.0.3", "@typescript-eslint/eslint-plugin": "^5.47.1", diff --git a/src/schema-accessor.ts b/src/schema-accessor.ts index 530d8bd..cd70681 100644 --- a/src/schema-accessor.ts +++ b/src/schema-accessor.ts @@ -34,17 +34,14 @@ export class InternalSchemaBasedAccessor implements SchemaAccessor { } async getStandardJsonSchema(options: Options = {}): Promise { - if (this.standardJSONSchema) return this.standardJSONSchema; - return this.standardJSONSchema = await convertors.internalSchemaToStandard(this.internalSchema, options); + return this.standardJSONSchema ??= await convertors.internalSchemaToStandard(this.internalSchema, options); } async getMongoDBJsonSchema(options: Options = {}): Promise { - if (this.mongodbJSONSchema) return this.mongodbJSONSchema; - return this.mongodbJSONSchema = await convertors.internalSchemaToMongoDB(this.internalSchema, options); + return this.mongodbJSONSchema ??= await convertors.internalSchemaToMongoDB(this.internalSchema, options); } async getExtendedJsonSchema(options: Options = {}): Promise { - if (this.extendedJSONSchema) return this.extendedJSONSchema; - return this.extendedJSONSchema = await convertors.internalSchemaToExtended(this.internalSchema, options); + return this.extendedJSONSchema ??= await convertors.internalSchemaToExtended(this.internalSchema, options); } }