From a89ffe1d2158ecdb3f0859a395b52450767089e6 Mon Sep 17 00:00:00 2001 From: Boris Cherny Date: Sun, 15 May 2022 22:29:29 -0700 Subject: [PATCH] Add reasonable max for tuple types (fix #438) --- README.md | 1 + src/cli.ts | 5 + src/index.ts | 11 + src/normalizer.ts | 53 +- src/optionValidator.ts | 7 + src/utils.ts | 7 + test/__snapshots__/test/test.ts.md | 1629 ++++++++++-------- test/__snapshots__/test/test.ts.snap | Bin 34980 -> 37467 bytes test/e2e/arrayMaxMinItems.ts | 22 - test/e2e/options.arrayIgnoreMaxMinItems.ts | 22 - test/e2e/realWorld.awsQuicksight.ts | 843 +++++++++ test/normalizer/removeMaxItems.1.json | 66 + test/normalizer/removeMaxItems.2.json | 71 + test/normalizer/removeMaxItems.3.json | 69 + test/normalizer/schemaIgnoreMaxMinItems.json | 52 +- test/normalizer/schemaItems.json | 7 + test/normalizer/schemaMinItems.json | 52 +- test/testNormalizer.ts | 9 +- 18 files changed, 2098 insertions(+), 828 deletions(-) create mode 100644 src/optionValidator.ts create mode 100644 test/e2e/realWorld.awsQuicksight.ts create mode 100644 test/normalizer/removeMaxItems.1.json create mode 100644 test/normalizer/removeMaxItems.2.json create mode 100644 test/normalizer/removeMaxItems.3.json diff --git a/README.md b/README.md index 71fabe06..cb0639a5 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,7 @@ See [server demo](example) and [browser demo](https://github.com/bcherny/json-sc | enableConstEnums | boolean | `true` | Prepend enums with [`const`](https://www.typescriptlang.org/docs/handbook/enums.html#computed-and-constant-members)? | | format | boolean | `true` | Format code? Set this to `false` to improve performance. | | ignoreMinAndMaxItems | boolean | `false` | Ignore maxItems and minItems for `array` types, preventing tuples being generated. | +| maxItems | number | `20` | Maximum number of unioned tuples to emit when representing bounded-size array types, before falling back to emitting unbounded arrays. Increase this to improve precision of emitted types, decrease it to improve performance, or set it to `-1` to ignore `maxItems`. | style | object | `{ bracketSpacing: false, printWidth: 120, semi: true, singleQuote: false, tabWidth: 2, trailingComma: 'none', useTabs: false }` | A [Prettier](https://prettier.io/docs/en/options.html) configuration | | unknownAny | boolean | `true` | Use `unknown` instead of `any` where possible | | unreachableDefinitions | boolean | `false` | Generates code for `definitions` that aren't referenced by the schema. | diff --git a/src/cli.ts b/src/cli.ts index 136fa738..c2c45f6f 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -161,6 +161,11 @@ Boolean values can be set to false using the 'no-' prefix. Prepend enums with 'const'? --format Format code? Set this to false to improve performance. + --maxItems + Maximum number of unioned tuples to emit when representing bounded-size + array types, before falling back to emitting unbounded arrays. Increase + this to improve precision of emitted types, decrease it to improve + performance, or set it to -1 to ignore minItems and maxItems. --style.XXX=YYY Prettier configuration --unknownAny diff --git a/src/index.ts b/src/index.ts index 26e17012..27c8be82 100644 --- a/src/index.ts +++ b/src/index.ts @@ -14,6 +14,7 @@ import {error, stripExtension, Try, log} from './utils' import {validate} from './validator' import {isDeepStrictEqual} from 'util' import {link} from './linker' +import {validateOptions} from './optionValidator' export {EnumJSONSchema, JSONSchema, NamedEnumJSONSchema, CustomTypeJSONSchema} from './types/JSONSchema' @@ -50,6 +51,13 @@ export interface Options { * Ignore maxItems and minItems for `array` types, preventing tuples being generated. */ ignoreMinAndMaxItems: boolean + /** + * Maximum number of unioned tuples to emit when representing bounded-size array types, + * before falling back to emitting unbounded arrays. Increase this to improve precision + * of emitted types, decrease it to improve performance, or set it to `-1` to ignore + * `minItems` and `maxItems`. + */ + maxItems: number /** * Append all index signatures with `| undefined` so that they are strictly typed. * @@ -84,6 +92,7 @@ export const DEFAULT_OPTIONS: Options = { enableConstEnums: true, format: true, ignoreMinAndMaxItems: false, + maxItems: 20, strictIndexSignatures: false, style: { bracketSpacing: false, @@ -115,6 +124,8 @@ export function compileFromFile(filename: string, options: Partial = DE } export async function compile(schema: JSONSchema4, name: string, options: Partial = {}): Promise { + validateOptions(options) + const _options = merge({}, DEFAULT_OPTIONS, options) const start = Date.now() diff --git a/src/normalizer.ts b/src/normalizer.ts index 6c8db2c2..57b496e2 100644 --- a/src/normalizer.ts +++ b/src/normalizer.ts @@ -1,5 +1,5 @@ import {JSONSchemaTypeName, LinkedJSONSchema, NormalizedJSONSchema, Parent} from './types/JSONSchema' -import {escapeBlockComment, justName, toSafeString, traverse} from './utils' +import {appendToDescription, escapeBlockComment, justName, toSafeString, traverse} from './utils' import {Options} from './' type Rule = (schema: LinkedJSONSchema, fileName: string, options: Options) => void @@ -57,18 +57,32 @@ rules.set('Default top level `id`', (schema, fileName) => { } }) -rules.set('Escape closing JSDoc Comment', schema => { +rules.set('Escape closing JSDoc comment', schema => { escapeBlockComment(schema) }) +rules.set('Add JSDoc comments for minItems and maxItems', schema => { + if (!isArrayType(schema)) { + return + } + const commentsToAppend = [ + 'minItems' in schema ? `@minItems ${schema.minItems}` : '', + 'maxItems' in schema ? `@maxItems ${schema.maxItems}` : '' + ].filter(Boolean) + if (commentsToAppend.length) { + schema.description = appendToDescription(schema.description, ...commentsToAppend) + } +}) + rules.set('Optionally remove maxItems and minItems', (schema, _fileName, options) => { - if (options.ignoreMinAndMaxItems) { - if ('maxItems' in schema) { - delete schema.maxItems - } - if ('minItems' in schema) { - delete schema.minItems - } + if (!isArrayType(schema)) { + return + } + if ('minItems' in schema && options.ignoreMinAndMaxItems) { + delete schema.minItems + } + if ('maxItems' in schema && (options.ignoreMinAndMaxItems || options.maxItems === -1)) { + delete schema.maxItems } }) @@ -77,13 +91,28 @@ rules.set('Normalize schema.minItems', (schema, _fileName, options) => { return } // make sure we only add the props onto array types - if (isArrayType(schema)) { - const {minItems} = schema - schema.minItems = typeof minItems === 'number' ? minItems : 0 + if (!isArrayType(schema)) { + return } + const {minItems} = schema + schema.minItems = typeof minItems === 'number' ? minItems : 0 // cannot normalize maxItems because maxItems = 0 has an actual meaning }) +rules.set('Remove maxItems if it is big enough to likely cause OOMs', (schema, _fileName, options) => { + if (options.ignoreMinAndMaxItems || options.maxItems === -1) { + return + } + if (!isArrayType(schema)) { + return + } + const {maxItems, minItems} = schema + // minItems is guaranteed to be a number after the previous rule runs + if (maxItems !== undefined && maxItems - (minItems as number) > options.maxItems) { + delete schema.maxItems + } +}) + rules.set('Normalize schema.items', (schema, _fileName, options) => { if (options.ignoreMinAndMaxItems) { return diff --git a/src/optionValidator.ts b/src/optionValidator.ts new file mode 100644 index 00000000..5eb8f44f --- /dev/null +++ b/src/optionValidator.ts @@ -0,0 +1,7 @@ +import {Options} from '.' + +export function validateOptions({maxItems}: Partial): void { + if (maxItems !== undefined && maxItems < -1) { + throw RangeError(`Expected options.maxItems to be >= -1, but was given ${maxItems}.`) + } +} diff --git a/src/utils.ts b/src/utils.ts index edae8f2e..184d3166 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -346,3 +346,10 @@ export function maybeStripNameHints(schema: JSONSchema): JSONSchema { } return schema } + +export function appendToDescription(existingDescription: string | undefined, ...values: string[]): string { + if (existingDescription) { + return `${existingDescription}\n\n${values.join('\n')}` + } + return values.join('\n') +} diff --git a/test/__snapshots__/test/test.ts.md b/test/__snapshots__/test/test.ts.md index bb0bcc06..c48a3d3d 100644 --- a/test/__snapshots__/test/test.ts.md +++ b/test/__snapshots__/test/test.ts.md @@ -17,7 +17,13 @@ Generated by [AVA](https://avajs.dev). ␊ export type PositiveInteger = number;␊ export type PositiveIntegerDefault0 = PositiveInteger;␊ + /**␊ + * @minItems 1␊ + */␊ export type SchemaArray = [HttpJsonSchemaOrgDraft04Schema, ...HttpJsonSchemaOrgDraft04Schema[]];␊ + /**␊ + * @minItems 1␊ + */␊ export type StringArray = [string, ...string[]];␊ export type SimpleTypes = "array" | "boolean" | "integer" | "null" | "number" | "object" | "string";␊ ␊ @@ -59,6 +65,9 @@ Generated by [AVA](https://avajs.dev). dependencies?: {␊ [k: string]: HttpJsonSchemaOrgDraft04Schema | StringArray;␊ };␊ + /**␊ + * @minItems 1␊ + */␊ enum?: [unknown, ...unknown[]];␊ type?: SimpleTypes | [SimpleTypes, ...SimpleTypes[]];␊ allOf?: SchemaArray;␊ @@ -423,15 +432,16 @@ Generated by [AVA](https://avajs.dev). export interface ArrayMaxMinItems {␊ array?: {␊ /**␊ - * minItems = 3␊ + * @minItems 3␊ */␊ withMinItems?: [string, string, string, ...string[]];␊ /**␊ - * maxItems = 3␊ + * @maxItems 3␊ */␊ withMaxItems?: [] | [string] | [string, string] | [string, string, string];␊ /**␊ - * minItems = 3, maxItems = 8␊ + * @minItems 3␊ + * @maxItems 8␊ */␊ withMinMaxItems?:␊ | [string, string, string]␊ @@ -441,29 +451,31 @@ Generated by [AVA](https://avajs.dev). | [string, string, string, string, string, string, string]␊ | [string, string, string, string, string, string, string, string];␊ /**␊ - * maxItems = 0␊ + * @maxItems 0␊ */␊ withMaxItems0?: [];␊ /**␊ - * minItems = 0␊ + * @minItems 0␊ */␊ withMinItems0?: string[];␊ /**␊ - * minItems = 0, maxItems = 0␊ + * @minItems 0␊ + * @maxItems 0␊ */␊ withMinMaxItems0?: [];␊ };␊ untyped?: {␊ /**␊ - * minItems = 3␊ + * @minItems 3␊ */␊ withMinItems?: [unknown, unknown, unknown, ...unknown[]];␊ /**␊ - * maxItems = 3␊ + * @maxItems 3␊ */␊ withMaxItems?: [] | [unknown] | [unknown, unknown] | [unknown, unknown, unknown];␊ /**␊ - * minItems = 3, maxItems = 8␊ + * @minItems 3␊ + * @maxItems 8␊ */␊ withMinMaxItems?:␊ | [unknown, unknown, unknown]␊ @@ -473,33 +485,34 @@ Generated by [AVA](https://avajs.dev). | [unknown, unknown, unknown, unknown, unknown, unknown, unknown]␊ | [unknown, unknown, unknown, unknown, unknown, unknown, unknown, unknown];␊ /**␊ - * maxItems = 0␊ + * @maxItems 0␊ */␊ withMaxItems0?: [];␊ /**␊ - * minItems = 0␊ + * @minItems 0␊ */␊ withMinItems0?: unknown[];␊ /**␊ - * minItems = 0, maxItems = 0␊ + * @minItems 0␊ + * @maxItems 0␊ */␊ withMinMaxItems0?: [];␊ };␊ tuple?: {␊ /**␊ - * minItems = 2␊ + * @minItems 2␊ */␊ withMinItemsLessThanItemLength?: [1, 2] | [1, 2, 3] | [1, 2, 3, 4] | [1, 2, 3, 4, 5] | [1, 2, 3, 4, 5, 6];␊ /**␊ - * minItems = 8␊ + * @minItems 8␊ */␊ withMinItemsGreaterThanItemLength?: [1, 2, 3, 4, 5, 6, ...unknown[]];␊ /**␊ - * maxItems = 2␊ + * @maxItems 2␊ */␊ withMaxItemsLessThanItemLength?: [] | [1] | [1, 2];␊ /**␊ - * maxItems = 8␊ + * @maxItems 8␊ */␊ withMaxItemsGreaterThanItemLength?:␊ | []␊ @@ -512,7 +525,8 @@ Generated by [AVA](https://avajs.dev). | [1, 2, 3, 4, 5, 6, unknown]␊ | [1, 2, 3, 4, 5, 6, unknown, unknown];␊ /**␊ - * minItems = 4, maxItems = 8␊ + * @minItems 4␊ + * @maxItems 8␊ */␊ withMinItemsLessThanItemLength_and_MaxItemsGreaterThanItemLength?:␊ | [1, 2, 3, 4]␊ @@ -521,26 +535,29 @@ Generated by [AVA](https://avajs.dev). | [1, 2, 3, 4, 5, 6, unknown]␊ | [1, 2, 3, 4, 5, 6, unknown, unknown];␊ /**␊ - * minItems = 2, maxItems = 4␊ + * @minItems 2␊ + * @maxItems 4␊ */␊ withMinItemsLessThanItemLength_and_MaxItemsLessThanItemLength?: [1, 2] | [1, 2, 3] | [1, 2, 3, 4];␊ /**␊ - * minItems = 8, maxItems = 10␊ + * @minItems 8␊ + * @maxItems 10␊ */␊ withMinItemsGreaterThanItemLength_and_MaxItemsGreaterThanItemLength?:␊ | [1, 2, 3, 4, 5, 6, unknown, unknown]␊ | [1, 2, 3, 4, 5, 6, unknown, unknown, unknown]␊ | [1, 2, 3, 4, 5, 6, unknown, unknown, unknown, unknown];␊ /**␊ - * maxItems = 0␊ + * @maxItems 0␊ */␊ withMaxItems0?: [];␊ /**␊ - * minItems = 0␊ + * @minItems 0␊ */␊ withMinItems0?: [] | [1] | [1, 2] | [1, 2, 3] | [1, 2, 3, 4] | [1, 2, 3, 4, 5] | [1, 2, 3, 4, 5, 6];␊ /**␊ - * minItems = 0, maxItems = 0␊ + * @minItems 0␊ + * @maxItems 0␊ */␊ withMinMaxItems0?: [];␊ };␊ @@ -589,6 +606,9 @@ Generated by [AVA](https://avajs.dev). export type ArrayOfSchema = {␊ description: string;␊ schema: unknown;␊ + /**␊ + * @minItems 1␊ + */␊ tests: [␊ {␊ description: string;␊ @@ -1464,7 +1484,13 @@ Generated by [AVA](https://avajs.dev). uniqueItems?: boolean;␊ maxProperties?: number;␊ minProperties?: number;␊ + /**␊ + * @minItems 1␊ + */␊ required?: [string, ...string[]];␊ + /**␊ + * @minItems 1␊ + */␊ enum?: [unknown, ...unknown[]];␊ type?: "array" | "boolean" | "integer" | "number" | "object" | "string";␊ not?: Schema | Reference;␊ @@ -1788,95 +1814,103 @@ Generated by [AVA](https://avajs.dev). export interface ArrayMaxMinItems {␊ array?: {␊ /**␊ - * minItems = 3␊ + * @minItems 3␊ */␊ withMinItems?: string[];␊ /**␊ - * maxItems = 3␊ + * @maxItems 3␊ */␊ withMaxItems?: string[];␊ /**␊ - * minItems = 3, maxItems = 8␊ + * @minItems 3␊ + * @maxItems 8␊ */␊ withMinMaxItems?: string[];␊ /**␊ - * maxItems = 0␊ + * @maxItems 0␊ */␊ withMaxItems0?: string[];␊ /**␊ - * minItems = 0␊ + * @minItems 0␊ */␊ withMinItems0?: string[];␊ /**␊ - * minItems = 0, maxItems = 0␊ + * @minItems 0␊ + * @maxItems 0␊ */␊ withMinMaxItems0?: string[];␊ };␊ untyped?: {␊ /**␊ - * minItems = 3␊ + * @minItems 3␊ */␊ withMinItems?: unknown[];␊ /**␊ - * maxItems = 3␊ + * @maxItems 3␊ */␊ withMaxItems?: unknown[];␊ /**␊ - * minItems = 3, maxItems = 8␊ + * @minItems 3␊ + * @maxItems 8␊ */␊ withMinMaxItems?: unknown[];␊ /**␊ - * maxItems = 0␊ + * @maxItems 0␊ */␊ withMaxItems0?: unknown[];␊ /**␊ - * minItems = 0␊ + * @minItems 0␊ */␊ withMinItems0?: unknown[];␊ /**␊ - * minItems = 0, maxItems = 0␊ + * @minItems 0␊ + * @maxItems 0␊ */␊ withMinMaxItems0?: unknown[];␊ };␊ tuple?: {␊ /**␊ - * minItems = 2␊ + * @minItems 2␊ */␊ withMinItemsLessThanItemLength?: [1, 2, 3, 4, 5, 6];␊ /**␊ - * minItems = 8␊ + * @minItems 8␊ */␊ withMinItemsGreaterThanItemLength?: [1, 2, 3, 4, 5, 6];␊ /**␊ - * maxItems = 2␊ + * @maxItems 2␊ */␊ withMaxItemsLessThanItemLength?: [1, 2, 3, 4, 5, 6];␊ /**␊ - * maxItems = 8␊ + * @maxItems 8␊ */␊ withMaxItemsGreaterThanItemLength?: [1, 2, 3, 4, 5, 6];␊ /**␊ - * minItems = 4, maxItems = 8␊ + * @minItems 4␊ + * @maxItems 8␊ */␊ withMinItemsLessThanItemLength_and_MaxItemsGreaterThanItemLength?: [1, 2, 3, 4, 5, 6];␊ /**␊ - * minItems = 2, maxItems = 4␊ + * @minItems 2␊ + * @maxItems 4␊ */␊ withMinItemsLessThanItemLength_and_MaxItemsLessThanItemLength?: [1, 2, 3, 4, 5, 6];␊ /**␊ - * minItems = 8, maxItems = 10␊ + * @minItems 8␊ + * @maxItems 10␊ */␊ withMinItemsGreaterThanItemLength_and_MaxItemsGreaterThanItemLength?: [1, 2, 3, 4, 5, 6];␊ /**␊ - * maxItems = 0␊ + * @maxItems 0␊ */␊ withMaxItems0?: [1, 2, 3, 4, 5, 6];␊ /**␊ - * minItems = 0␊ + * @minItems 0␊ */␊ withMinItems0?: [1, 2, 3, 4, 5, 6];␊ /**␊ - * minItems = 0, maxItems = 0␊ + * @minItems 0␊ + * @maxItems 0␊ */␊ withMinMaxItems0?: [1, 2, 3, 4, 5, 6];␊ };␊ @@ -2200,6 +2234,785 @@ Generated by [AVA](https://avajs.dev). }␊ ` +## realWorld.awsQuicksight.js + +> Expected output to match snapshot for e2e test: realWorld.awsQuicksight.js + + `/* tslint:disable */␊ + /**␊ + * This file was automatically generated by json-schema-to-typescript.␊ + * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,␊ + * and run json-schema-to-typescript to regenerate this file.␊ + */␊ + ␊ + export type GeoSpatialCountryCode = "US";␊ + export type DataSetImportMode = "SPICE" | "DIRECT_QUERY";␊ + export type GeoSpatialDataRole =␊ + | "COUNTRY"␊ + | "STATE"␊ + | "COUNTY"␊ + | "CITY"␊ + | "POSTCODE"␊ + | "LONGITUDE"␊ + | "LATITUDE"␊ + | "POLITICAL1";␊ + export type ColumnDataType = "STRING" | "INTEGER" | "DECIMAL" | "DATETIME";␊ + export type JoinType = "INNER" | "OUTER" | "LEFT" | "RIGHT";␊ + export type InputColumnDataType = "STRING" | "INTEGER" | "DECIMAL" | "DATETIME" | "BIT" | "BOOLEAN" | "JSON";␊ + export type TextQualifier = "DOUBLE_QUOTE" | "SINGLE_QUOTE";␊ + export type FileFormat = "CSV" | "TSV" | "CLF" | "ELF" | "XLSX" | "JSON";␊ + export type RowLevelPermissionPolicy = "GRANT_ACCESS" | "DENY_ACCESS";␊ + export type RowLevelPermissionFormatVersion = "VERSION_1" | "VERSION_2";␊ + ␊ + /**␊ + * Definition of the AWS::QuickSight::DataSet Resource Type.␊ + */␊ + export interface RealWorld {␊ + /**␊ + *

The Amazon Resource Name (ARN) of the resource.

␊ + */␊ + Arn?: string;␊ + AwsAccountId?: string;␊ + /**␊ + *

Groupings of columns that work together in certain QuickSight features. Currently, only geospatial hierarchy is supported.

␊ + *␊ + * @minItems 1␊ + * @maxItems 8␊ + */␊ + ColumnGroups?:␊ + | [ColumnGroup]␊ + | [ColumnGroup, ColumnGroup]␊ + | [ColumnGroup, ColumnGroup, ColumnGroup]␊ + | [ColumnGroup, ColumnGroup, ColumnGroup, ColumnGroup]␊ + | [ColumnGroup, ColumnGroup, ColumnGroup, ColumnGroup, ColumnGroup]␊ + | [ColumnGroup, ColumnGroup, ColumnGroup, ColumnGroup, ColumnGroup, ColumnGroup]␊ + | [ColumnGroup, ColumnGroup, ColumnGroup, ColumnGroup, ColumnGroup, ColumnGroup, ColumnGroup]␊ + | [ColumnGroup, ColumnGroup, ColumnGroup, ColumnGroup, ColumnGroup, ColumnGroup, ColumnGroup, ColumnGroup];␊ + /**␊ + * @minItems 1␊ + */␊ + ColumnLevelPermissionRules?: [ColumnLevelPermissionRule, ...ColumnLevelPermissionRule[]];␊ + /**␊ + *

The amount of SPICE capacity used by this dataset. This is 0 if the dataset isn't␊ + * imported into SPICE.

␊ + */␊ + ConsumedSpiceCapacityInBytes?: number;␊ + /**␊ + *

The time that this dataset was created.

␊ + */␊ + CreatedTime?: string;␊ + DataSetId?: string;␊ + FieldFolders?: FieldFolderMap;␊ + ImportMode?: DataSetImportMode;␊ + /**␊ + *

The last time that this dataset was updated.

␊ + */␊ + LastUpdatedTime?: string;␊ + LogicalTableMap?: LogicalTableMap;␊ + /**␊ + *

The display name for the dataset.

␊ + */␊ + Name?: string;␊ + /**␊ + *

The list of columns after all transforms. These columns are available in templates,␊ + * analyses, and dashboards.

␊ + */␊ + OutputColumns?: OutputColumn[];␊ + /**␊ + *

A list of resource permissions on the dataset.

␊ + *␊ + * @minItems 1␊ + * @maxItems 64␊ + */␊ + Permissions?: [ResourcePermission, ...ResourcePermission[]];␊ + PhysicalTableMap?: PhysicalTableMap;␊ + RowLevelPermissionDataSet?: RowLevelPermissionDataSet;␊ + /**␊ + *

Contains a map of the key-value pairs for the resource tag or tags assigned to the dataset.

␊ + *␊ + * @minItems 1␊ + * @maxItems 200␊ + */␊ + Tags?: [Tag, ...Tag[]];␊ + IngestionWaitPolicy?: IngestionWaitPolicy;␊ + }␊ + /**␊ + *

Groupings of columns that work together in certain Amazon QuickSight features. This is␊ + * a variant type structure. For this structure to be valid, only one of the attributes can␊ + * be non-null.

␊ + */␊ + export interface ColumnGroup {␊ + GeoSpatialColumnGroup?: GeoSpatialColumnGroup;␊ + [k: string]: unknown;␊ + }␊ + /**␊ + *

Geospatial column group that denotes a hierarchy.

␊ + */␊ + export interface GeoSpatialColumnGroup {␊ + /**␊ + *

Columns in this hierarchy.

␊ + *␊ + * @minItems 1␊ + * @maxItems 16␊ + */␊ + Columns:␊ + | [string]␊ + | [string, string]␊ + | [string, string, string]␊ + | [string, string, string, string]␊ + | [string, string, string, string, string]␊ + | [string, string, string, string, string, string]␊ + | [string, string, string, string, string, string, string]␊ + | [string, string, string, string, string, string, string, string]␊ + | [string, string, string, string, string, string, string, string, string]␊ + | [string, string, string, string, string, string, string, string, string, string]␊ + | [string, string, string, string, string, string, string, string, string, string, string]␊ + | [string, string, string, string, string, string, string, string, string, string, string, string]␊ + | [string, string, string, string, string, string, string, string, string, string, string, string, string]␊ + | [string, string, string, string, string, string, string, string, string, string, string, string, string, string]␊ + | [␊ + string,␊ + string,␊ + string,␊ + string,␊ + string,␊ + string,␊ + string,␊ + string,␊ + string,␊ + string,␊ + string,␊ + string,␊ + string,␊ + string,␊ + string␊ + ]␊ + | [␊ + string,␊ + string,␊ + string,␊ + string,␊ + string,␊ + string,␊ + string,␊ + string,␊ + string,␊ + string,␊ + string,␊ + string,␊ + string,␊ + string,␊ + string,␊ + string␊ + ];␊ + CountryCode?: GeoSpatialCountryCode;␊ + /**␊ + *

A display name for the hierarchy.

␊ + */␊ + Name: string;␊ + [k: string]: unknown;␊ + }␊ + export interface ColumnLevelPermissionRule {␊ + /**␊ + * @minItems 1␊ + */␊ + ColumnNames?: [string, ...string[]];␊ + /**␊ + * @minItems 1␊ + * @maxItems 100␊ + */␊ + Principals?: [string, ...string[]];␊ + [k: string]: unknown;␊ + }␊ + export interface FieldFolderMap {␊ + [k: string]: FieldFolder;␊ + }␊ + /**␊ + * This interface was referenced by \`FieldFolderMap\`'s JSON-Schema definition␊ + * via the \`patternProperty\` ".+".␊ + */␊ + export interface FieldFolder {␊ + Description?: string;␊ + /**␊ + * @minItems 0␊ + * @maxItems 5000␊ + */␊ + Columns?: string[];␊ + [k: string]: unknown;␊ + }␊ + export interface LogicalTableMap {␊ + [k: string]: LogicalTable;␊ + }␊ + /**␊ + *

A logical table is a unit that joins and that data␊ + * transformations operate on. A logical table has a source, which can be either a physical␊ + * table or result of a join. When a logical table points to a physical table, the logical␊ + * table acts as a mutable copy of that physical table through transform operations.

␊ + *␊ + * This interface was referenced by \`LogicalTableMap\`'s JSON-Schema definition␊ + * via the \`patternProperty\` "[0-9a-zA-Z-]*".␊ + */␊ + export interface LogicalTable {␊ + /**␊ + *

A display name for the logical table.

␊ + */␊ + Alias: string;␊ + /**␊ + *

Transform operations that act on this logical table.

␊ + *␊ + * @minItems 1␊ + * @maxItems 2048␊ + */␊ + DataTransforms?: [TransformOperation, ...TransformOperation[]];␊ + Source: LogicalTableSource;␊ + [k: string]: unknown;␊ + }␊ + /**␊ + *

A data transformation on a logical table. This is a variant type structure. For this␊ + * structure to be valid, only one of the attributes can be non-null.

␊ + */␊ + export interface TransformOperation {␊ + TagColumnOperation?: TagColumnOperation;␊ + FilterOperation?: FilterOperation;␊ + CastColumnTypeOperation?: CastColumnTypeOperation;␊ + CreateColumnsOperation?: CreateColumnsOperation;␊ + RenameColumnOperation?: RenameColumnOperation;␊ + ProjectOperation?: ProjectOperation;␊ + [k: string]: unknown;␊ + }␊ + /**␊ + *

A transform operation that tags a column with additional information.

␊ + */␊ + export interface TagColumnOperation {␊ + /**␊ + *

The column that this operation acts on.

␊ + */␊ + ColumnName: string;␊ + /**␊ + *

The dataset column tag, currently only used for geospatial type tagging. .

␊ + * ␊ + *

This is not tags for the AWS tagging feature. .

␊ + *
␊ + *␊ + * @minItems 1␊ + * @maxItems 16␊ + */␊ + Tags:␊ + | [ColumnTag]␊ + | [ColumnTag, ColumnTag]␊ + | [ColumnTag, ColumnTag, ColumnTag]␊ + | [ColumnTag, ColumnTag, ColumnTag, ColumnTag]␊ + | [ColumnTag, ColumnTag, ColumnTag, ColumnTag, ColumnTag]␊ + | [ColumnTag, ColumnTag, ColumnTag, ColumnTag, ColumnTag, ColumnTag]␊ + | [ColumnTag, ColumnTag, ColumnTag, ColumnTag, ColumnTag, ColumnTag, ColumnTag]␊ + | [ColumnTag, ColumnTag, ColumnTag, ColumnTag, ColumnTag, ColumnTag, ColumnTag, ColumnTag]␊ + | [ColumnTag, ColumnTag, ColumnTag, ColumnTag, ColumnTag, ColumnTag, ColumnTag, ColumnTag, ColumnTag]␊ + | [ColumnTag, ColumnTag, ColumnTag, ColumnTag, ColumnTag, ColumnTag, ColumnTag, ColumnTag, ColumnTag, ColumnTag]␊ + | [␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag␊ + ]␊ + | [␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag␊ + ]␊ + | [␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag␊ + ]␊ + | [␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag␊ + ]␊ + | [␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag␊ + ]␊ + | [␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag,␊ + ColumnTag␊ + ];␊ + [k: string]: unknown;␊ + }␊ + /**␊ + *

A tag for a column in a TagColumnOperation structure. This is a␊ + * variant type structure. For this structure to be valid, only one of the attributes can␊ + * be non-null.

␊ + */␊ + export interface ColumnTag {␊ + ColumnGeographicRole?: GeoSpatialDataRole;␊ + ColumnDescription?: ColumnDescription;␊ + [k: string]: unknown;␊ + }␊ + /**␊ + *

Metadata that contains a description for a column.

␊ + */␊ + export interface ColumnDescription {␊ + /**␊ + *

The text of a description for a column.

␊ + */␊ + Text?: string;␊ + [k: string]: unknown;␊ + }␊ + /**␊ + *

A transform operation that filters rows based on a condition.

␊ + */␊ + export interface FilterOperation {␊ + /**␊ + *

An expression that must evaluate to a Boolean value. Rows for which the expression␊ + * evaluates to true are kept in the dataset.

␊ + */␊ + ConditionExpression: string;␊ + [k: string]: unknown;␊ + }␊ + /**␊ + *

A transform operation that casts a column to a different type.

␊ + */␊ + export interface CastColumnTypeOperation {␊ + /**␊ + *

Column name.

␊ + */␊ + ColumnName: string;␊ + /**␊ + *

When casting a column from string to datetime type, you can supply a string in a␊ + * format supported by Amazon QuickSight to denote the source data format.

␊ + */␊ + Format?: string;␊ + NewColumnType: ColumnDataType;␊ + [k: string]: unknown;␊ + }␊ + /**␊ + *

A transform operation that creates calculated columns. Columns created in one such␊ + * operation form a lexical closure.

␊ + */␊ + export interface CreateColumnsOperation {␊ + /**␊ + *

Calculated columns to create.

␊ + *␊ + * @minItems 1␊ + * @maxItems 128␊ + */␊ + Columns: [CalculatedColumn, ...CalculatedColumn[]];␊ + [k: string]: unknown;␊ + }␊ + /**␊ + *

A calculated column for a dataset.

␊ + */␊ + export interface CalculatedColumn {␊ + /**␊ + *

A unique ID to identify a calculated column. During a dataset update, if the column ID␊ + * of a calculated column matches that of an existing calculated column, Amazon QuickSight␊ + * preserves the existing calculated column.

␊ + */␊ + ColumnId: string;␊ + /**␊ + *

Column name.

␊ + */␊ + ColumnName: string;␊ + /**␊ + *

An expression that defines the calculated column.

␊ + */␊ + Expression: string;␊ + [k: string]: unknown;␊ + }␊ + /**␊ + *

A transform operation that renames a column.

␊ + */␊ + export interface RenameColumnOperation {␊ + /**␊ + *

The new name for the column.

␊ + */␊ + NewColumnName: string;␊ + /**␊ + *

The name of the column to be renamed.

␊ + */␊ + ColumnName: string;␊ + [k: string]: unknown;␊ + }␊ + /**␊ + *

A transform operation that projects columns. Operations that come after a projection␊ + * can only refer to projected columns.

␊ + */␊ + export interface ProjectOperation {␊ + /**␊ + *

Projected columns.

␊ + *␊ + * @minItems 1␊ + * @maxItems 2000␊ + */␊ + ProjectedColumns: [string, ...string[]];␊ + [k: string]: unknown;␊ + }␊ + /**␊ + *

Information about the source of a logical table. This is a variant type structure. For␊ + * this structure to be valid, only one of the attributes can be non-null.

␊ + */␊ + export interface LogicalTableSource {␊ + /**␊ + *

Physical table ID.

␊ + */␊ + PhysicalTableId?: string;␊ + JoinInstruction?: JoinInstruction;␊ + [k: string]: unknown;␊ + }␊ + /**␊ + *

Join instruction.

␊ + */␊ + export interface JoinInstruction {␊ + /**␊ + *

On Clause.

␊ + */␊ + OnClause: string;␊ + Type: JoinType;␊ + LeftJoinKeyProperties?: JoinKeyProperties;␊ + /**␊ + *

Left operand.

␊ + */␊ + LeftOperand: string;␊ + /**␊ + *

Right operand.

␊ + */␊ + RightOperand: string;␊ + RightJoinKeyProperties?: JoinKeyProperties;␊ + [k: string]: unknown;␊ + }␊ + export interface JoinKeyProperties {␊ + UniqueKey?: boolean;␊ + [k: string]: unknown;␊ + }␊ + /**␊ + *

Output column.

␊ + */␊ + export interface OutputColumn {␊ + Type?: ColumnDataType;␊ + /**␊ + *

A description for a column.

␊ + */␊ + Description?: string;␊ + /**␊ + *

A display name for the dataset.

␊ + */␊ + Name?: string;␊ + [k: string]: unknown;␊ + }␊ + /**␊ + *

Permission for the resource.

␊ + */␊ + export interface ResourcePermission {␊ + /**␊ + *

The IAM action to grant or revoke permissions on.

␊ + *␊ + * @minItems 1␊ + * @maxItems 16␊ + */␊ + Actions:␊ + | [string]␊ + | [string, string]␊ + | [string, string, string]␊ + | [string, string, string, string]␊ + | [string, string, string, string, string]␊ + | [string, string, string, string, string, string]␊ + | [string, string, string, string, string, string, string]␊ + | [string, string, string, string, string, string, string, string]␊ + | [string, string, string, string, string, string, string, string, string]␊ + | [string, string, string, string, string, string, string, string, string, string]␊ + | [string, string, string, string, string, string, string, string, string, string, string]␊ + | [string, string, string, string, string, string, string, string, string, string, string, string]␊ + | [string, string, string, string, string, string, string, string, string, string, string, string, string]␊ + | [string, string, string, string, string, string, string, string, string, string, string, string, string, string]␊ + | [␊ + string,␊ + string,␊ + string,␊ + string,␊ + string,␊ + string,␊ + string,␊ + string,␊ + string,␊ + string,␊ + string,␊ + string,␊ + string,␊ + string,␊ + string␊ + ]␊ + | [␊ + string,␊ + string,␊ + string,␊ + string,␊ + string,␊ + string,␊ + string,␊ + string,␊ + string,␊ + string,␊ + string,␊ + string,␊ + string,␊ + string,␊ + string,␊ + string␊ + ];␊ + /**␊ + *

The Amazon Resource Name (ARN) of the principal. This can be one of the␊ + * following:

␊ + *
    ␊ + *
  • ␊ + *

    The ARN of an Amazon QuickSight user or group associated with a data source or dataset. (This is common.)

    ␊ + *
  • ␊ + *
  • ␊ + *

    The ARN of an Amazon QuickSight user, group, or namespace associated with an analysis, dashboard, template, or theme. (This is common.)

    ␊ + *
  • ␊ + *
  • ␊ + *

    The ARN of an AWS account root: This is an IAM ARN rather than a QuickSight␊ + * ARN. Use this option only to share resources (templates) across AWS accounts.␊ + * (This is less common.)

    ␊ + *
  • ␊ + *
␊ + */␊ + Principal: string;␊ + [k: string]: unknown;␊ + }␊ + export interface PhysicalTableMap {␊ + [k: string]: PhysicalTable;␊ + }␊ + /**␊ + *

A view of a data source that contains information about the shape of the data in the␊ + * underlying source. This is a variant type structure. For this structure to be valid,␊ + * only one of the attributes can be non-null.

␊ + *␊ + * This interface was referenced by \`PhysicalTableMap\`'s JSON-Schema definition␊ + * via the \`patternProperty\` "[0-9a-zA-Z-]*".␊ + */␊ + export interface PhysicalTable {␊ + RelationalTable?: RelationalTable;␊ + CustomSql?: CustomSql;␊ + S3Source?: S3Source;␊ + [k: string]: unknown;␊ + }␊ + /**␊ + *

A physical table type for relational data sources.

␊ + */␊ + export interface RelationalTable {␊ + /**␊ + *

The Amazon Resource Name (ARN) for the data source.

␊ + */␊ + DataSourceArn: string;␊ + /**␊ + *

The column schema of the table.

␊ + *␊ + * @minItems 1␊ + * @maxItems 2048␊ + */␊ + InputColumns: [InputColumn, ...InputColumn[]];␊ + /**␊ + *

The schema name. This name applies to certain relational database engines.

␊ + */␊ + Schema?: string;␊ + /**␊ + *

The catalog associated with a table.

␊ + */␊ + Catalog?: string;␊ + /**␊ + *

The name of the relational table.

␊ + */␊ + Name: string;␊ + [k: string]: unknown;␊ + }␊ + /**␊ + *

Metadata for a column that is used as the input of a transform operation.

␊ + */␊ + export interface InputColumn {␊ + Type: InputColumnDataType;␊ + /**␊ + *

The name of this column in the underlying data source.

␊ + */␊ + Name: string;␊ + [k: string]: unknown;␊ + }␊ + /**␊ + *

A physical table type built from the results of the custom SQL query.

␊ + */␊ + export interface CustomSql {␊ + /**␊ + *

The Amazon Resource Name (ARN) of the data source.

␊ + */␊ + DataSourceArn: string;␊ + /**␊ + *

The SQL query.

␊ + */␊ + SqlQuery: string;␊ + /**␊ + *

The column schema from the SQL query result set.

␊ + *␊ + * @minItems 1␊ + * @maxItems 2048␊ + */␊ + Columns: [InputColumn, ...InputColumn[]];␊ + /**␊ + *

A display name for the SQL query result.

␊ + */␊ + Name: string;␊ + [k: string]: unknown;␊ + }␊ + /**␊ + *

A physical table type for as S3 data source.

␊ + */␊ + export interface S3Source {␊ + /**␊ + *

The amazon Resource Name (ARN) for the data source.

␊ + */␊ + DataSourceArn: string;␊ + /**␊ + *

A physical table type for as S3 data source.

␊ + *␊ + * @minItems 1␊ + * @maxItems 2048␊ + */␊ + InputColumns: [InputColumn, ...InputColumn[]];␊ + UploadSettings?: UploadSettings;␊ + [k: string]: unknown;␊ + }␊ + /**␊ + *

Information about the format for a source file or files.

␊ + */␊ + export interface UploadSettings {␊ + /**␊ + *

Whether the file has a header row, or the files each have a header row.

␊ + */␊ + ContainsHeader?: boolean;␊ + TextQualifier?: TextQualifier;␊ + Format?: FileFormat;␊ + /**␊ + *

A row number to start reading data from.

␊ + */␊ + StartFromRow?: number;␊ + /**␊ + *

The delimiter between values in the file.

␊ + */␊ + Delimiter?: string;␊ + [k: string]: unknown;␊ + }␊ + /**␊ + *

The row-level security configuration for the dataset.

␊ + */␊ + export interface RowLevelPermissionDataSet {␊ + /**␊ + *

The Amazon Resource Name (ARN) of the permission dataset.

␊ + */␊ + Arn: string;␊ + /**␊ + *

The namespace associated with the row-level permissions dataset.

␊ + */␊ + Namespace?: string;␊ + PermissionPolicy: RowLevelPermissionPolicy;␊ + FormatVersion?: RowLevelPermissionFormatVersion;␊ + [k: string]: unknown;␊ + }␊ + /**␊ + *

The key or keys of the key-value pairs for the resource tag or tags assigned to the␊ + * resource.

␊ + */␊ + export interface Tag {␊ + /**␊ + *

Tag value.

␊ + */␊ + Value: string;␊ + /**␊ + *

Tag key.

␊ + */␊ + Key: string;␊ + [k: string]: unknown;␊ + }␊ + /**␊ + *

Wait policy to use when creating/updating dataset. Default is to wait for SPICE ingestion to finish with timeout of 36 hours.

␊ + */␊ + export interface IngestionWaitPolicy {␊ + /**␊ + *

Wait for SPICE ingestion to finish to mark dataset creation/update successful. Default (true).␊ + * Applicable only when DataSetImportMode mode is set to SPICE.

␊ + */␊ + WaitForSpiceIngestion?: boolean;␊ + /**␊ + *

The maximum time (in hours) to wait for Ingestion to complete. Default timeout is 36 hours.␊ + * Applicable only when DataSetImportMode mode is set to SPICE and WaitForSpiceIngestion is set to true.

␊ + */␊ + IngestionWaitTimeInHours?: number;␊ + [k: string]: unknown;␊ + }␊ + ` + ## realWorld.heroku.js > Expected output to match snapshot for e2e test: realWorld.heroku.js @@ -5823,6 +6636,9 @@ Generated by [AVA](https://avajs.dev). };␊ propertyNames?: CoreSchemaMetaSchema2;␊ const?: true;␊ + /**␊ + * @minItems 1␊ + */␊ enum?: [true, ...unknown[]];␊ type?: SimpleTypes | [SimpleTypes, ...SimpleTypes[]];␊ format?: string;␊ @@ -5838,6 +6654,9 @@ Generated by [AVA](https://avajs.dev). [k: string]: unknown;␊ }␊ | boolean;␊ + /**␊ + * @minItems 1␊ + */␊ export type SchemaArray = [CoreSchemaMetaSchema2, ...CoreSchemaMetaSchema2[]];␊ export type StringArray = string[];␊ export type SimpleTypes = "array" | "boolean" | "integer" | "null" | "number" | "object" | "string";␊ @@ -5885,6 +6704,9 @@ Generated by [AVA](https://avajs.dev). };␊ propertyNames?: CoreSchemaMetaSchema2;␊ const?: true;␊ + /**␊ + * @minItems 1␊ + */␊ enum?: [true, ...unknown[]];␊ type?: SimpleTypes | [SimpleTypes, ...SimpleTypes[]];␊ format?: string;␊ @@ -6242,7 +7064,13 @@ Generated by [AVA](https://avajs.dev). uniqueItems?: boolean;␊ maxProperties?: number;␊ minProperties?: number;␊ + /**␊ + * @minItems 1␊ + */␊ required?: [string, ...string[]];␊ + /**␊ + * @minItems 1␊ + */␊ enum?: [unknown, ...unknown[]];␊ type?: "array" | "boolean" | "integer" | "number" | "object" | "string";␊ not?: Schema | Reference;␊ @@ -10029,6 +10857,9 @@ Generated by [AVA](https://avajs.dev). [k: string]: unknown;␊ }␊ export interface ExampleSchema {␊ + /**␊ + * @maxItems 5␊ + */␊ b?:␊ | []␊ | [number]␊ @@ -10611,7 +11442,13 @@ Generated by [AVA](https://avajs.dev). ␊ export interface Union {␊ test?: {␊ + /**␊ + * @minItems 1␊ + */␊ test1?: boolean | [string, ...string[]];␊ + /**␊ + * @minItems 1␊ + */␊ test2?: boolean | [string, ...string[]];␊ [k: string]: unknown;␊ };␊ @@ -11296,707 +12133,3 @@ Generated by [AVA](https://avajs.dev). g?: number;␊ }␊ ` - -## Add empty `required` property if none is defined - -> Snapshot 1 - - `{␊ - "id": "foo",␊ - "type": "object",␊ - "properties": {␊ - "a": {␊ - "type": "integer",␊ - "id": "a"␊ - }␊ - },␊ - "additionalProperties": true,␊ - "required": []␊ - }` - -## Normalize const to singleton enum - -> Snapshot 1 - - `{␊ - "id": "foo",␊ - "enum": [␊ - "foobar"␊ - ]␊ - }` - -## Default additionalProperties to false - -> Snapshot 1 - - `{␊ - "id": "foo",␊ - "type": "object",␊ - "properties": {␊ - "a": {␊ - "type": "integer",␊ - "id": "a"␊ - },␊ - "b": {␊ - "type": "object",␊ - "required": [],␊ - "additionalProperties": false␊ - }␊ - },␊ - "required": [],␊ - "additionalProperties": false␊ - }` - -## Default additionalProperties to true - -> Snapshot 1 - - `{␊ - "id": "foo",␊ - "type": "object",␊ - "properties": {␊ - "a": {␊ - "type": "integer",␊ - "id": "a"␊ - }␊ - },␊ - "required": [],␊ - "additionalProperties": true␊ - }` - -## Default top level `id` - -> Snapshot 1 - - `{␊ - "friend": {␊ - "properties": {␊ - "knowsFrom": {␊ - "enum": [␊ - "work",␊ - "school",␊ - "other"␊ - ]␊ - }␊ - },␊ - "additionalProperties": true,␊ - "required": [],␊ - "id": "friend"␊ - },␊ - "properties": {␊ - "firstName": {␊ - "type": "string"␊ - }␊ - },␊ - "additionalProperties": true,␊ - "required": [␊ - "firstName"␊ - ],␊ - "id": "DefaultID"␊ - }` - -## Normalize $defs to definitions - -> Snapshot 1 - - `{␊ - "id": "foo",␊ - "definitions": {␊ - "bar": "baz"␊ - }␊ - }` - -## Destructure unary types - -> Snapshot 1 - - `{␊ - "id": "foo",␊ - "type": "object",␊ - "definitions": {␊ - "a": {␊ - "type": "integer",␊ - "id": "a"␊ - }␊ - },␊ - "properties": {␊ - "b": {␊ - "type": "string",␊ - "id": "b"␊ - }␊ - },␊ - "additionalProperties": true,␊ - "required": []␊ - }` - -## Normalize empty const to singleton enum - -> Snapshot 1 - - `{␊ - "id": "foo",␊ - "enum": [␊ - ""␊ - ]␊ - }` - -## Non object items.items - -> Snapshot 1 - - `{␊ - "id": "foo",␊ - "type": "object",␊ - "properties": {␊ - "myProperty": {␊ - "type": "array",␊ - "items": "string",␊ - "minItems": 0␊ - }␊ - },␊ - "additionalProperties": false,␊ - "required": []␊ - }` - -## Normalize extends to an array - -> Snapshot 1 - - `{␊ - "id": "foo",␊ - "extends": [␊ - "foo"␊ - ],␊ - "type": "object",␊ - "required": [],␊ - "additionalProperties": true␊ - }` - -## Remove `enum=[null]` if `type=['null']` - -> Snapshot 1 - - `{␊ - "type": "object",␊ - "properties": {␊ - "noopMissingType": {␊ - "enum": [␊ - "foo",␊ - "bar"␊ - ]␊ - },␊ - "noopMissingEnum": {␊ - "type": [␊ - "null",␊ - "string"␊ - ]␊ - },␊ - "noopNonNullableEnum": {␊ - "type": "string",␊ - "enum": [␊ - "foo",␊ - "bar",␊ - null␊ - ]␊ - },␊ - "dedupeNulls": {␊ - "type": "string",␊ - "enum": [␊ - "foo",␊ - "bar",␊ - null␊ - ]␊ - }␊ - },␊ - "required": [],␊ - "additionalProperties": true,␊ - "id": "RedundantNull"␊ - }` - -## Remove empty extends (1) - -> Snapshot 1 - - `{␊ - "id": "foo",␊ - "type": "object",␊ - "required": [],␊ - "additionalProperties": true␊ - }` - -## Remove empty extends (2) - -> Snapshot 1 - - `{␊ - "id": "foo",␊ - "type": "object",␊ - "required": [],␊ - "additionalProperties": true␊ - }` - -## Normalise ignoreMinAndMaxItems - -> Snapshot 1 - - `{␊ - "id": "foo",␊ - "type": "object",␊ - "properties": {␊ - "untyped": {␊ - "type": "object",␊ - "properties": {␊ - "unbounded": {␊ - "type": "array"␊ - },␊ - "minOnly": {␊ - "type": "array"␊ - },␊ - "maxOnly": {␊ - "type": "array"␊ - },␊ - "minAndMax": {␊ - "type": "array"␊ - }␊ - },␊ - "additionalProperties": false,␊ - "required": []␊ - },␊ - "untypedArray": {␊ - "type": "object",␊ - "properties": {␊ - "unbounded": {␊ - "type": [␊ - "array",␊ - "string"␊ - ]␊ - },␊ - "minOnly": {␊ - "type": [␊ - "array",␊ - "string"␊ - ]␊ - },␊ - "maxOnly": {␊ - "type": [␊ - "array",␊ - "string"␊ - ]␊ - },␊ - "minAndMax": {␊ - "type": [␊ - "array",␊ - "string"␊ - ]␊ - }␊ - },␊ - "additionalProperties": false,␊ - "required": []␊ - },␊ - "typed": {␊ - "type": "object",␊ - "properties": {␊ - "unbounded": {␊ - "items": {␊ - "type": "string"␊ - }␊ - },␊ - "minOnly": {␊ - "items": {␊ - "type": "string"␊ - },␊ - "additionalItems": {␊ - "type": "string"␊ - }␊ - },␊ - "maxOnly": {␊ - "items": {␊ - "type": "string"␊ - }␊ - },␊ - "minAndMax": {␊ - "items": {␊ - "type": "string"␊ - }␊ - }␊ - },␊ - "additionalProperties": false,␊ - "required": []␊ - },␊ - "anyOf": {␊ - "type": "object",␊ - "properties": {␊ - "unbounded": {␊ - "anyOf": [␊ - {␊ - "items": {␊ - "type": "string"␊ - }␊ - }␊ - ],␊ - "additionalProperties": false,␊ - "required": []␊ - },␊ - "minOnly": {␊ - "anyOf": [␊ - {␊ - "items": {␊ - "type": "string"␊ - },␊ - "additionalItems": {␊ - "type": "string"␊ - }␊ - }␊ - ],␊ - "additionalProperties": false,␊ - "required": []␊ - },␊ - "maxOnly": {␊ - "anyOf": [␊ - {␊ - "items": {␊ - "type": "string"␊ - }␊ - }␊ - ],␊ - "additionalProperties": false,␊ - "required": []␊ - },␊ - "minAndMax": {␊ - "anyOf": [␊ - {␊ - "items": {␊ - "type": "string"␊ - }␊ - }␊ - ],␊ - "additionalProperties": false,␊ - "required": []␊ - }␊ - },␊ - "additionalProperties": false,␊ - "required": []␊ - }␊ - },␊ - "additionalProperties": false,␊ - "required": []␊ - }` - -## Normalize schema.items - -> Snapshot 1 - - `{␊ - "id": "foo",␊ - "type": "object",␊ - "properties": {␊ - "untypedUnbounded": {␊ - "type": "array",␊ - "minItems": 0␊ - },␊ - "typedUnbounded": {␊ - "items": {␊ - "type": "string"␊ - },␊ - "minItems": 0␊ - },␊ - "typedMinBounded": {␊ - "items": [␊ - {␊ - "type": "string"␊ - },␊ - {␊ - "type": "string"␊ - }␊ - ],␊ - "minItems": 2,␊ - "additionalItems": {␊ - "type": "string"␊ - }␊ - },␊ - "typedMaxBounded": {␊ - "items": [␊ - {␊ - "type": "string"␊ - },␊ - {␊ - "type": "string"␊ - }␊ - ],␊ - "maxItems": 2,␊ - "minItems": 0␊ - },␊ - "typedMinMaxBounded": {␊ - "items": [␊ - {␊ - "type": "string"␊ - },␊ - {␊ - "type": "string"␊ - },␊ - {␊ - "type": "string"␊ - },␊ - {␊ - "type": "string"␊ - },␊ - {␊ - "type": "string"␊ - }␊ - ],␊ - "minItems": 2,␊ - "maxItems": 5␊ - },␊ - "moreItemsThanMax": {␊ - "items": [␊ - {␊ - "type": "string"␊ - }␊ - ],␊ - "maxItems": 1,␊ - "minItems": 0␊ - },␊ - "itemAnyOf": {␊ - "items": [␊ - {␊ - "anyOf": [␊ - {␊ - "type": "string"␊ - },␊ - {␊ - "type": "number"␊ - }␊ - ],␊ - "additionalProperties": false,␊ - "required": []␊ - }␊ - ],␊ - "maxItems": 1,␊ - "minItems": 0␊ - },␊ - "baseAnyOf": {␊ - "anyOf": [␊ - {␊ - "items": [␊ - {␊ - "type": "string"␊ - }␊ - ],␊ - "maxItems": 1,␊ - "minItems": 0␊ - },␊ - {␊ - "items": [␊ - {␊ - "type": "number"␊ - },␊ - {␊ - "type": "number"␊ - }␊ - ],␊ - "maxItems": 2,␊ - "minItems": 0␊ - }␊ - ],␊ - "additionalProperties": false,␊ - "required": []␊ - }␊ - },␊ - "additionalProperties": false,␊ - "required": []␊ - }` - -## Normalise schema.minItems - -> Snapshot 1 - - `{␊ - "id": "foo",␊ - "type": "object",␊ - "properties": {␊ - "untyped": {␊ - "type": "object",␊ - "properties": {␊ - "unbounded": {␊ - "type": "array",␊ - "minItems": 0␊ - },␊ - "minOnly": {␊ - "type": "array",␊ - "minItems": 1␊ - },␊ - "maxOnly": {␊ - "type": "array",␊ - "maxItems": 2,␊ - "minItems": 0␊ - },␊ - "minAndMax": {␊ - "type": "array",␊ - "minItems": 1,␊ - "maxItems": 2␊ - }␊ - },␊ - "additionalProperties": false,␊ - "required": []␊ - },␊ - "untypedArray": {␊ - "type": "object",␊ - "properties": {␊ - "unbounded": {␊ - "type": [␊ - "array",␊ - "string"␊ - ],␊ - "minItems": 0␊ - },␊ - "minOnly": {␊ - "type": [␊ - "array",␊ - "string"␊ - ],␊ - "minItems": 1␊ - },␊ - "maxOnly": {␊ - "type": [␊ - "array",␊ - "string"␊ - ],␊ - "maxItems": 2,␊ - "minItems": 0␊ - },␊ - "minAndMax": {␊ - "type": [␊ - "array",␊ - "string"␊ - ],␊ - "minItems": 1,␊ - "maxItems": 2␊ - }␊ - },␊ - "additionalProperties": false,␊ - "required": []␊ - },␊ - "typed": {␊ - "type": "object",␊ - "properties": {␊ - "unbounded": {␊ - "items": {␊ - "type": "string"␊ - },␊ - "minItems": 0␊ - },␊ - "minOnly": {␊ - "items": [␊ - {␊ - "type": "string"␊ - }␊ - ],␊ - "additionalItems": {␊ - "type": "string"␊ - },␊ - "minItems": 1␊ - },␊ - "maxOnly": {␊ - "items": [␊ - {␊ - "type": "string"␊ - },␊ - {␊ - "type": "string"␊ - }␊ - ],␊ - "maxItems": 2,␊ - "minItems": 0␊ - },␊ - "minAndMax": {␊ - "items": [␊ - {␊ - "type": "string"␊ - },␊ - {␊ - "type": "string"␊ - }␊ - ],␊ - "minItems": 1,␊ - "maxItems": 2␊ - }␊ - },␊ - "additionalProperties": false,␊ - "required": []␊ - },␊ - "anyOf": {␊ - "type": "object",␊ - "properties": {␊ - "unbounded": {␊ - "anyOf": [␊ - {␊ - "items": {␊ - "type": "string"␊ - },␊ - "minItems": 0␊ - }␊ - ],␊ - "additionalProperties": false,␊ - "required": []␊ - },␊ - "minOnly": {␊ - "anyOf": [␊ - {␊ - "items": [␊ - {␊ - "type": "string"␊ - }␊ - ],␊ - "additionalItems": {␊ - "type": "string"␊ - },␊ - "minItems": 1␊ - }␊ - ],␊ - "additionalProperties": false,␊ - "required": []␊ - },␊ - "maxOnly": {␊ - "anyOf": [␊ - {␊ - "items": [␊ - {␊ - "type": "string"␊ - },␊ - {␊ - "type": "string"␊ - }␊ - ],␊ - "maxItems": 2,␊ - "minItems": 0␊ - }␊ - ],␊ - "additionalProperties": false,␊ - "required": []␊ - },␊ - "minAndMax": {␊ - "anyOf": [␊ - {␊ - "items": [␊ - {␊ - "type": "string"␊ - },␊ - {␊ - "type": "string"␊ - }␊ - ],␊ - "minItems": 1,␊ - "maxItems": 2␊ - }␊ - ],␊ - "additionalProperties": false,␊ - "required": []␊ - }␊ - },␊ - "additionalProperties": false,␊ - "required": []␊ - }␊ - },␊ - "additionalProperties": false,␊ - "required": []␊ - }` diff --git a/test/__snapshots__/test/test.ts.snap b/test/__snapshots__/test/test.ts.snap index 8bf57c85758c2ebe42d6f9e85f8a00250323d282..5bfe27d0bb3bbd4ec1062c30f1ae04f69eefba9e 100644 GIT binary patch literal 37467 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 literal 34980 zcmV(vK;t1GjIWFA%BJDoK( zxlA&%irtyX+$6L5$f{v_gc})N>ERyj2g#^r3Ohew0X^yh7U~B9(u?**kRSmXKo0^W z2!iw|NYM473xXg>5U_wA^c`mAX71)5?!hyQL3CGoxZCmBXPYZ>*rmM3fZY$~!*8cy?dY-Vf6d%m;hJ=@vZe)21Cd(V6HEANYq z=UeOEcAVwH4_3WN5`+gcFCPmpONw+PymA}_!74W7$AOm?adUTGo_MKHph0sIegxyr z%8EFdCMgtx^4^Oi3-jaQX(aX# zQ&3^xW6gng>J5fT5(z)1=a9!j&v6k&@&VC8kIC>GG0N$YyBU1CqG)9^Nn!4I!X_g3 z<@^xhB_P;*df>z4wvX2P?TY7x!NUh0_wp(H`~f#-y(5CR-UN~k!X&P|r+I^SMf^5S zj$?c|fj1!_W#<6itI3Dg{z*6~Ce}M~GKz`}X8W1`DDg%$!nmb|{%F?lPo9eSFdxI~ z8X-}GO`jD7VzH^8148YQ`auxl@cn2z7n7{)7ACD7>sULKb>_^^sY&2+JgPhQa2mdv zqbcI>H-)G`EgOH4CR35-p=j=*t%%u8Dt=RhsX*#77LkoQtF1ox13H80#zwFvlCkH# zeyir^>v@R9Cf?D^ngE=k877by=hIpsrXmhRJX)|JBpVy!)U1eUb-b1%NzEN3A?bD4K5BJzhKI{EDJ z$rN}eh|8qNrv*tW5T>KCr$n@Okffft4^m5H`2)|A<5IZCzXU?DlvWY9nZyU-VF7x;ULv)Fz2u1>Wr8M~I03EKp?(^J+$Q5A8Ta`w`~Ae{L`a64;g-3lHr&%GdJt{bBpNG8%}hHCnbI!cu$hV`=R&9Pn~m#Ux@}yF*US=Q?&{- zRjs0D{f~Rkx|~!!$*5<$C;6XRll;Hk@JU8I*^_)qGlT#Aw#QUI>^9d>Y~Zu+hyFVn zP;DQru)(oE8NB|w7Y_j-so|mjEwn(?IhUpMCoV}$lDH!J{W3`!?4bYNBC!ARCK4FA z{SZS;U!T

r&|ILdob)79t}_HjU8viSD-L3RIZP}#!5 z(C~}}*4`d@$t@H!Kn=LkA8O4*G4_u_(5$gAY1z=CyMLRnw03Vm zIR*nEPB@%_dYq<7P>ck<4T>pX3N`X=)s4IF3IlU@uBwd^upVgZ)hktJssg$!*oya1 zLV`LAkN4>jHCp)baXH1#Chna>8w|%2MEGakCs^}Ic!U*yjL*B_2|WI!v;jZwZ3DXP zJ!uYR^!b^8@=Qi8I8DL7@sVW;{xg4LX$l%BV}Ag?bnU3Ba1bH|e#aZB$6-ExR>q3x zsHW<_c9c`Kbs37{ZoQ0CVMRc)u<}v$;&`P$)%!F?v}!`|$FA{}K$MzuLr?Px^e(t? zg)>(?w+33Kp+x-M#;LzcbKf?Fj=J*WUCm49w6Hn{mXZicaHPWmS7C6bWupUW>JJVT zdEuoa8#14DPtKR+*9%xc&7E~9vsmFX);h21=iW}+JYB{Lv((S?Ut&2ZRASBoyWa@l zQ;}tRW1oKL7|qvU)3WajA6C7O&F59`lgiIk@5l8wtKLsq2kcx4^zrjlfRs+%P?_!b zSpN=# zrW^nJWIq3En1_AP>-IaN@;ySyeG4U@EQ*rFmTv2sv;e!;%+{QKQGuFCl z8Bt?67t4GXl{VT)-CW2>wXIMU1WccH4$xM1Z+`zDmTmgq-NeoBifzi+GIl57*MrjK z!1G0lL91z4`Y67h=S(>VKS@_r7Nl*#CVK35=pEHcVu} zbl`*;N03Y>E%#(?8sRi#59F?y+Jb7RPM-kxwOywpKMI4&Zk62LGB&o(rB%|tknnN2 zNUD3ZAk`W4B`I%ee{s^?e`L|!zw^DDN_U${5yK?XQ9eE^XU=L|*&k?d)#EHSvP)x! zWu!U-&Zs*!45<~VJ$$VmBn{cywM{#~?K`S!m-#~4UUfFsw5!|^&<;UMfB$T2rltts z=CWH6_{Y|I`Il}YpRQ3hVym_}$_fBaz5NDvDsS;Cpg$&y+x&4t4b0he??MoZif%da zk{rUJpM@j$cEyMPuSE&}^G&1#;+#+A{wXj{#V^ibmsz!X{dQxSz<%17z%(hTtOBDV z12SmlH2=FrU;pimqAxkDXa3YXNRx@2O02|FVs6(G5yH#@s{s;(Dt}_Li$8VI_HKaQ1{bh$eiw$ujp>IJSTA5`|M9mY9v@6K9E44 z41y%`+Om7p z2OWwbK0sQ(i*Ybtg+uY$7Pr}AND3rn;MmWMogyptc>z;OXD{do&JLxC5=r% z`)sCTra;>2NpVoDjn(?0NTVfVQhR$p>a%Cft8rS=Ij`SX^ZNS6&g-KNvspR5??1HG zIG$;G)M42!HpA9DDr=p-w0O5Z{KT5wf8i$1Zehv^^Wjghmg1gVX!_-?ygc z|G81Zzdk)NAZ)fn`M@fC)0G3s*i{1sLa=_|32MaStYStzSya^^WR_hcMpJPBEHfT4 z65kXtRTjaUk1`tnnnXaYP46i530ZIK+(@%G-r&z(`)l8Bto{1#+E4e_|HpszAKv-; zkA5&%xAyuhDpYDT<6;YlWD{_An544@hKjxMB1x%-=NyY$FRfJScj}>8?|!HClcx3H z*iowYNZ{=e&3@($_BI|peLUbeTM-5LYUk0<_yrh_`1{GL=bM8w_!IQHvKE>D9px4 z9rBSVCcwN{_>vyZOfyE(h(pn|;r*BX8;fH8^S^XcDF$cfNt#Ryj{I5uOty=g%MI&H zTUpMt+?Zi46v1wLDe0Hw?|E7Xqv|8)H_p<>FW2x4?p^r*J)_!oa|yO7rD3>sZ(V;} zzpoG48r2`lZGYpH(NFc$18>{?!Km|v05m2zKS_}(IPTviK%~K_?8O62Fyw-Yj*Hlk zwLm3HJ3zxqxJ>rOe!iK&l16ISD9M53PnAZnl1w-_Ll&_S%TcfpTd2KO>$*8|!WiVj z0Tc~0*7Zwtla{_?THN^qZR~bWH~qA!!f^N+1*{^4?(yG`?1r)cPyqWcXi@!z(l=wDk- zQEiG=>7V--wjf{aums7ZNxKgckEBCqsm5Re9&z+!*m40KJ|8gQ~0SU6UlGLPwu@XSxwD5bwU%4 zt%Er-qVHsfq<#<j0~EDDttOI~3{*_mw-{0)uKw`OQF`aUQlLClTV<1om_ z4tCQ!>6J;Zl7@dnFlK_n0-6#7|0fn9|9dx)Tbg-mOib z<*nP!m`X>E#hQ%a%owd@HaQ-%waga#U>&?~qc7RiNW@7y4I$z?7VZ4~8^r`$Xy?`j zCh)us|EWx+HD^W?&$&6j+g;x$YwYPJKX-#~xrMYB%Q7QrzFXz=u%kl8_>RBUv1U zvYc1Et;eEDZ22q9R z1RKDT8V}U|O_tB-gz*3{mH|Nkj6}qq*Qt1wzvjybn{Wpb3XZ7x3B}}-> zDJ-`w5rvZwh>%`Q!)fIWMnmz2-e55(#z37St%Fe+aKA=JN%A%n4P)!HVP*w{h#>SS zkkUoScG)jzI9(~ea@&#^6=^6pn1!U6jThTL7c=`4efVN;?}g*_&PI`s@4G%sMZ6tA z$1zNn{k<}TTEi9MCB8uT912*2Y41tW4U`+6ZBc{Wwm8-5{1Q(g@tTttOCfK^(E}>I zT@VD}K`0mH$Ln|3f4T0~!twH!42xq`e;Q^x>EVu_eSB9YrMi3Xr*}WO%XVYJMJ&BP zJ^)*C8~#h~^%InxezcX0aKr3z`Ln=FIDF*+&qR6z0)`@W@rk3vGC3Rcnjc>>1Hj7i z9HLL*-Fv<~gn+yS%$OJW5B?q{lPU1SIOh{N>PJttp(9c*TB&etR~~S`aUB~Di5cw7%`BG8wQDmf-ssxQwg z(#ZM^Acgju9^;ceUH%Z|4Cx`Zjj+dfWV4q)9w)!39vrRCqk>%ZQ+MorFnMhy;LK-&D0@rAysm+CWTVZ-R5NLVFgpWZ;dyt z*4J>^SIo_yBVF+<1oaip!4H~3Jx^jXH>t6c*co5oGC1}=N8a1GW~;6xIY3d)ujAglK_0kt&Hmeqt^K25j5vIE6M zsB$9Q_3ASbg>ln*cnY7KUG$nK9_dwBHvs)_TNsai|FR-#Eso^COZ7aP&6kX??ebZ( zgWmR4{Pqg$VZ|J45?qP31~XduP&f#dz;zy8xPqeyU#)+&wm;`2g1%q5z6`XOd5?xu zs#K?%3+Vwl2><;Wk=7pckd)r~o(@Rr%??%*zPDpCM7JJSRoJ~>BVuW+2a{Rb0`Kdf zs+%89ec}BY5=zcePpTOM@7G|IKwd;EE2Z)k_^Qf-r?d-UX+{%Jq(fkMI|o+YjER2| zPGoul^-lX9p6QQa4GMCQ+Kq* z87F9axYZ`Q#um-|`e$k5169r`LDx*SmIx(g-7ri|Ji0vK%?h9E?qz2`@N7(LlNo^f z?0#NxvM5{9Fe6mH44YVj5L*Spz%)egY0Lc0l;HY`?}K!p_k8^EEMudOxb2NwteDHr|{^ept4x&apGF{fGGENBfg+G6WdG$ ztc54mD?mgV4vSn==N!O2gR=zyyNcaB_CAx@*ux)rB-7nE=vZaKS#ZaX;JJK6xMEw( zKxcm%!uNq96g#}4j2%KY&B07`oV1MnIfwl(7l@aSC|6LAiKxWK?=N~6XzUZZaT|w+j6?Gh*YYy#|y#)`zry?7_s)SNxBLF4q zB02g5$yA}cimlWN?eN-5-ils`=_FHoV5SDv75GkFi{*M?#|hdM$hbxhF?W?+ISQL$ zzXHzR9KLEvLbKRFZibX^UUds4>bHT}1lPqQ={$}%80WjDlwm@F;XdB=?^>rD{>>Y8 zyi1+lLsx>A9O%UhgD5hQdSQ^Q*Ny_bf-l_MP&v_K@>;nk_ieu&QhmXFa<8fQwuJePU=abKEJw4)Bs(QnKZv{g(S zl9hgM)gr2Y{>GjF-2_>o=)ioxWxRL9x&q!ceQYRt+CU;Ca~I89JaA09kNE?c2t6FA z^0*J9zIIo3-Cn+)XFI#sUr_(45u(bbfdPjTkmt)Qtma%{)p`@g4r7rLaPzSs$LV)E z$4pd4#MmhuNpvXHNLAf!+AgVMd*=kPNK4Y&Tm8~0U^9!_f}2QfEkq^dSE{B--)Hct z62b;y!0$&`RI|c4)BEYd)2k=<Yj*5~}M{-@TQ{|A5dM$h?1 zb2A)#p_|N`8(8o{@=hSNUyIrWrc1w~-fZ%`E~;<2=ey(db-F3M z-~4p~s(k{x-Cy21gBNiHy4B`|-h_UccbcE;E#|!%?|qGVPvl(eMc_Swx$rBvyVJ~t z-?`nB4(42P-S3|1R<3ZdcUC(aH}A0i2a9M@ty+`Pul_kzQpBhjZDQVB$~5lOtp3Vh zSen&8`71YCvs&iv{to5tCU=Iu0sMg{KkZnrG47dW(SEJt4(s(dtk=4}{aVL9I_g`m zG5ZbIw_Y#vddI!;de_@>PWGaZxk$tW4d}W^2L^nD1Ne7P0y)USlR+Dx6{MZ{4>U=7dNq@o4M)`Ieh?Cv$F!u8zZMr`0wKefiZ?+e5*M&D)&J%w&Y}vKY zK1zMM#?X;pEIPqW)2O!T%W|`(ZTfGm>3w?>r+4AC{rmOB{ris9{rm09yZ2swbyjN* z=OP9hbu`A=D=%1S*l?|6E4{HBuAT09f8|1~&PU50v4+dm=WJ~??MHM@!Quq15`ktV zVJV~0-k?p_kWgjA4pw>SidK1O-(^2%Yh_`FKqFO4`aiP6=TedA3y_cluAjSKwq}Xsv=92R*Ip1RB_Hiq@ed6YPKeNc~(;KB+ULNt> zUHfU3a!93pPP~;#r;HlBYNF;;=R~Utv}T1{Ez$F&M_z7wQWI|XtMl=PF5k}@#AqhBOx6s(U$n!GJsWc2F~ zKK$^3Nl4%S(T6u?uRv3g@TQTUqx&6m9C%_fO^!vH0i7I)2yvTXLvplYRo=BGFSnTt z!x%3TK@?NWg_i)-DdkoSMbdG3$Km|vx(iY}w8jgt5vJZ!GAN#AvG!2Ep3 z;CB@|nAQ+`^QZnWjKX}@T>B*z-P9#@8*+-8Ys%XuRE6e(P+~f5pSI~#O&OP^&7P2; zXh853PtsGFC#vwS$hkUHDyC(%UHr*)=#dNMsUK&+51X3bliydMa6^%m!LR@Z2k6d< z$bj<^zJ((6?@Ri)LM7cLWHVEL^mZ+TH4Y5JZ=CW+s_3>+GFurXn0+WoWtyQ{wN2yu z%7Dpm?Z|hJo~iIlJexO4MG!g{&?bFZ31HdNMMbp&Tl8gR5X|CaEepSOPyH5r-Gz@U zSgfhQ3h)~DGJbqS%j>`g#ucnlF=sbVsDLURM!;#-U}7_OVfvn}XfkvbQXf|aAsx%l zXKT|mISPXYn%b77UdTdFFCGF90{SUHA~g{DHkWzHMOMQ2D9jsS+SXsO@uLKm=Nha| zpig6`1^`1-_R_6T6rsGuFpRgz%`=ea4kq-!kwddnjCJWL=9LjgZ`T6 z8%pl-=M_!`vu33gaMq!t{MG?~RhN^ZG*{xp3aa!WEcuqgpW|m$mJ%8?m)*n9P&PgE zV+qq*3!mIE%1NGSR|SS;F7f$|OsDpeuQu1Eg-We94sO=etlX+yQtsRaOfs&vku=Gq zN&`f&cI}CvqKz?yIF?Wz>Bi%irL7#deCK&&*um`vXEj41C<#FzoII(m0m&p%UJ;4uMALaUZV>HoqfK9&rk8|3aewzGV}!s;3bbv zSYGm{l`JX_UEg=%{mLMlWNR|#qqESnU3NP_$v9jC{d}5)4XkeW`SxS^eTA(HXDRx! z!WSzN34yL{i5asn7TTcisz&TL^p0PjiyVmct&~iph_RltqVnsx>p|mLG-q_XPs`DP zdj8f~2tTY0FfYa2g^x)q%mqI<9)~$l514AfS_f777iICsq#iT{Q0a@sJ!#c=k{^Q+ zH^r5Y+1q_(YXRrayi)%M>(0;NckB&?$I)|ONT;5(VFR+A{j%vKmJM|^&}_pC%ryz_ z@mSOWM)PuuW3QWPS!c~vJs|SD zu?Br~joCeC#Wc`!CZAn%M)_kfuPM1lR09YdqdLrhug>8gb3(9 z15jkp=Q9=-{Oa?*eYIcrC1ft080b3)K{YS@$jidR7*pX)5fm5@buHJH@`v0!GIRG9Z&tdt0D}Y9G z%^D;EGinn*I9n=l)MK?uBBj~zq~T%E9^=cNswzqV&76NI13&}mGec+6P((?5$j+wN zQ^u61ttqAlS)=RPi!IO`%dXZBaHJdtkP*i$A*38e>#`NDvahT`X!O=^Tj3zzo2utc z%^{gERg}qUn~FD>#T<;GVR5)$%VQw7os@w=Q)c2Qa_}*gQNQ?o9}GV758N`2wi^u| z;2{$QInKToLC3K~fds#y0nlxvx424apcL)%m*(0vO3#XH3YZ`tT-|!KsyU@icAo5c$cr%(LFztGQ`k3 zt?GgF(BBHgZCzQGzzrgzCKRHFDO#1(4bl+GMigu$eu-?X7HF0;x{4X^x9cnmOJ6$h zulaJC2U2?5ZDn`FsS2?%5M;+lkI2%eQyPV@>y!2y8dQ529`QOr0hK5Hpf7>Z^rv|@ zvLNb{C3X-vIdw$}l@-FEN}z{PGNc`(3Z)VcC@Y#drBzk682!>$?)h1kj6xDwv|vf{ zm=I5=bHSZXyDF)&WGDI4h)LA97&vK;caWvJ%6uU0@|{4{z?zt48p|ZDvifBsc0M6o zC}x@U*A`TN_0ECsTC-iofsD>w8*#^9oa0p3FU#xP`?|F96x@=hSh?!$4#?;z5z&~$ z5rBSk$RZDbM&-TaA0-KgaY+}*p6L3&6UGwMk)~%A*7o`2U7AAP5z5-^MoDlTxf!?8 zs7oT7;oYL0O(e^uA%Bqq_tX30vefFBg`i0}76Hi1(BI@$>6aa3a4+#2hF zjB+crM2KG}`zGSX@k{I0!|C<1F$@hSf6LFt!^BSmsTYGWQ>$HFR>I?*Us??QTcJ4& zN-ZFAJKm1{qLFnrQa$PSt;=F0};o-~X9k}lZIy6)kPD&8Zsg|Wcr z8(IzW$&ChPam>mmbd{l_j6H>&!xWr5>Rsej)4qKZrJ3fkBzo!Gle918kGHFtVpdEM z{0z*}@CcaNe#~B0+m%2X%f572&fWT->)7rz>na$;m})gIMDi0@PB1d9dMbD2begSu z%A1?fX+*6#>oz4?Sk;qS54w_UL#fvUDNdFq==eLE|Vu zY_P&NVs*VH%KSyfeAoFliS&iy0wS7xyH9Pm_fTR`<>i&uc1mOW~Pvn|Q>)x}mpEmgt zouoETIhwQJ6^FO1xI>W~rv7vcj5$65GPoPD&<`jn`?T!1_qrj#Tt$S_Bd zOTkPK+al@NN9vU*)pOyGN{ESMGFu<<2 z>q&!J)iQ{nLXf8x%Thn~9l-F;uoM^E3aF^sC0$XUOvf*2O$MW(--c@%-Z&jC7v){K zCDsquQPELW_U$t{RyNp$d=cRl&}{$E3LP9>4XZGKJVQuD*~(m<#2rpiZJ=W)g#rC} zgi%zW=)@oUgilmTw}nnr=H(*(xxK0L`4n1jI>xHdhCPbM-oVy}gft4@z z@r7cdLBYp4kY$4As;(-g-v_A>^e|3_!WXQO+oHfDB2Z- zzRE{C(NKs0TD<^W3EX)o#JtYvs7ED?$KtYv*Az<@8E>Tmr#TAKBt~ww>XBlZtuj5* zTxSM)L$#~8j%TUB0F6OL!m!FScMVioJ$N!-wPPq-yng1Wd+>Zm&5m4&RKFvUf>Nbi zEj3X2JyAFx#9-0|PNbBDtQd`e>6nTE0Gp|8vl23t1l$I5DtH90wLgJn#MeVLxW+8q zO;YLAtJ4}PA}ozPI_^V_sZ&8pL1_oJtk<&0n9fq{rFJ4@%YMR@76(L19Tf9 zf?}8mYK@Kzt!)Rc;ugHOnH4a;_W7l)2f1lQ<6Wd_l4dm{F^rG=C=43-5A~_u>~j+i z1B_3okyuW$98~ovnMqE^l1jg|!fNE?OUdZ2%4KTgh%_KhLd+i;i1rq+*#3wwA?A3k zj=^XcJ2pdoBH|DvB4(gjz`AtUWJz=cd`*5()8TQR&w7B=CZpwqfR0kDhvRGXJK$~%7RlJUK7EuC5}einGJuVu_h*HiUH}g zD7RCs%4&bIilYT$SNn#Rb`OAIx9upLA|rGTLw~)FLm{i6NNMY#G^FDCOd4(mLpI^A z#x&RNg%KXfsd*Nv6m~9JrLo3|ZKb$DF=1V0mK5GG2_(#ph>}QhG=ScSO>Zl;gWSIL*LBaX$Fh(c?12Q5 zf3z|my+Y8ZgL=tumJ5rD@#{W*@avogOjMUKfz^1xIUGpW>%f7m zxWl>uonq?;YJ&_V02;ZV4GNGUro)q8&5fCAq^Xh>UQ0IH^`wCqRyl0x$nO|sK*B~D zJs4{V%#%gAv}i~)`dqG6OgmC}xTC)7HvQ6;zj3yFW&R{ug)xf`TUS#p9^N3bhv~su zsP8iK;|4xbGq}#Fru41}U^4PYr6c%F4e&P@2atwCj0Tkli1ZqvliWOD>d_?Ky>iJ& z?3eK*SeTDY0p`{vjba(1(cQhRomYEAm+<)b<;#*NH@GUwRAV)2m`YIQq5JjMojE~O zpC3t8hHVGX!YZOAV?mcEE;G@&UyH&)=!9h3*{m6iW*I>+u zi{Vp|#@;Q?yXLvdGX->5Z?C_0hDb8D&+2bz<y>r zE!RQ@sqp-o5|aw;52Ivgt}_hRobs-lHyR5dxMHG+yxJ8GgU&8ev>Aq1&~^s3WEBS0CpLhj33Qqw4(wUL z@AGBJ+|%w082r6XlUL+2NfR^f*>{lvLysF21iO*>4<=N_oJF(r|a0#)|{^EC2Q4wRH%=bfN)7M&OKmzu&q7pzZJZe z5q7sP=aHA0E3FzGAWyK%xLNms;Dv*=%%p3!E@**N*95P@ZjA+Dv-Z>p1hXv(i>_BD z8$;&VJ=vJCotZ>BaK11^q|BuE(skjMT}n55;Y>P%+jA(M>9NnttFrn)ZF zMk=$7Un_pt0(8B3QEpUYERU5PSQ#s2ZjfR4&M31kCxAUn)GCue;N}!1#*XnUT6rE< zof0FLMU#3xbVeORq0yEnppuklsU?s=?%*DWb9-PlJH&UluTT(N~8a?Qd5=o7dEY}g!>PI&mkVR?W*mb@iZ#ICU5;)z_ z+c2gez5(mSta21to=gUfqv~k*m3Ak=$9M)FInteLE3_L$&*DUdTuVPLF^x>77vkJz zXe(10^IU_;?l4(*wys!xDO0ehA7u%aKj3six%a?(J86y_D&dyL z{ZLbq>V^E`RPb`vRpYFfOf{r3fci1w62_8YFb@(nrbeeGq33<9oYjWjvcjy9ySV*? z)4v^fFE^f{1pE9E6$O<&p)Vhcm0;0 zc@9J7C6VrDb2Es}OR1Bq24YgO(m1|I-@;)QVev?>8=^gx081tlWO>SaOnx<>AYRcX=~S!er8Kh$eb;@ zcIk_5jr28vFR8uL{@G<}L3-g~Zahj+_`n-r7Kp%4gSC6V9PmLz8Lwi4UD z3t~a-84P{e{HZzM*!%=80W-@PEkT#TM$*wlBfLB@J$M(nfkhhn5v6)nX!QJp z1D&!{H_YmRPpO4(HReM;ZOSyz^ufry=qdud!u{HL9`Lm3ke0g*9fW`C-1c`=vRuKA z@6zIPeL=S3cyC-{^l~~?|H_-J)GvKy6=g9(x^sKC+05ieASFIqYTl4U zFBG-dzv#v-d{e!ghrv+Ih1RiGZ0VFbdkO(s* ztAI`UV~(T1o;@j~K3 zAMZV;!GHdkqusuEys=!TNPIbZq zbPJd}F_VG%k$8w!tW1~@d9@NDm30Pc3JR0|O zK3MZ}E=~xu#ir$6-n3xQWuj@3s>uW&bzj|C%;kzLTkEvhuBBczmd<=Wu)-gBzZzMQ zOhk`-5I@P~N*U2+ymf>d66~VG#plPE21mwamRm{xH+`)nLLT5r^uyBYo%0o$y`i9r3Ibnqejt78qxi|4;w$U&&N3 zC74y4+gmR&&roTU^SAjS5CmV49Qh(Yo&JtrUrZ)TWEW~0ahDv#0x z3Q~ehc^Nb3PRH=#j>Kcxd}lv0r!{gbDx=?~vbD_~#v~)Ogn@QR@J#)X-pQTb5%7<7 z)pmdk%tT zp`>!-aJo-*n>FKpXA&I|LWsaHv-UWEqC|{*9OJ)1N5JC{O5rog?W=P2VPAYWmg4?( z+)2KFYasMC73WrhRWPWViZ#MKdqP_kByHVGVx_`DYiHHUtw@B&~Xx7!{l}Scbe)Ch0PT zTDEFaBUq=v^U~P+^2KJEq`50sBX@EoB?d!!Ry*e$&vjdp#EjHZ$GoZPgn8z{qvCul}Uzw>Qpk3pij3ODC}%H!ILn`N$X1m>y3U? z-Xv1q`H71cy}KNBBQI%F=AuuFM&zbfjS9%p`UEGw1C_TJvB#%0&!tr)%}~;rm8W;z z^B()7G3E~gKs9XT1M!}03SEUNd%HRs6Ut+7@&*BNI8sN_;{t6{<}W>7>>2Y1dg%DH zz?NqdBh>VDE5jrRWx7y|Y#E1n&RYijxky6~p3<2YiTE%dv#!ks(W*Bra?>It^Kg<0 z&{!A_AoT@!Ifa%-E7CSIp>r8Mw?$XSWGH82iM$@WCpd1o#BJv zi?hlDBxk?bdAsbeObWuw%7R5+oW-}Gj;hz9@{4_0%pvxqFHSeuWl1%t$yXPF(q;A% zy1PpPS4rBS!^-Vl5P9P%?;FS_TBq+zblvdWVc8AYY&m}t42((?x$c%yR@_s@GQQfs zS3^}>-TPME`;B!+`fNG7&?`}6e60%?s9saUVVW*hI1#x|5f*n4D4BEGiX?@_aEKwp z3Jzux=r?MF^xJSst_}7SCFpBVsZE;DqJqiX@oEQ=e`v1CDn%$yiMk=063Hv0a9@_* zm!-Q~K_%%)Lns#$3Ub0bJSYJ{k_5Hh`A~2ekD?+F83lWX@|Irdz3jn766-!OJ_@9K zpeoGMoEZ6SpGwy3NX0Lbo)?74e#wQ}&@X>$=(k1S8f`epldc#mbKfh_W$Pqv)IHwy z=x-U3FLyoVK|8&gQ1_Ik)MPG0imS95DnWO&L^Wz{P5s%#aEz4FUAA*e zdO%iHy4r&xT9w=Mb}*+sRQ4&7Ljh-r9aVf54N0zL(mE2!*~IV9#mrP{rB=DS`-S%w zzf?67V(HXkArt##-Tj4SRMWrg0 zbFWVu#!i zIjp8hH155UgCZ_(RDv(lNSriXu@qa#J3F)8*(gw4OPMS~4@x;dlIh3T%c!^~nb+vs z)v{bkcDw`z_d@9)A04;kIsMS=mes`eXnq5RCQ7dQ85!U_v66(>aZ%w; zol@YMccwEz$_<&JjE}72eHHyQek`@UNM_LQmcoo$V+?T3CKQ-u%G2WR3%r!?{eTh{ z1u!klc>DwO(Oa-NkVtvH)e1_oUtTC!wyuOJ^*`essVmhH!;lcYXbH(g)`4+8e?tE4@Z6 z9894D$kAp{f+wx2C^4;~_l?=~LF*og=F+z+L)A<($Yt*=^^oC3P{ccmtcI$^&R@3Y3t^j~y9= zdqf>#@vAGWqxJK$>g;VcfJ)HLYWOUeXjWY?_f>cQe0#SxlYq8a`Z)oQZ**PQLWVoi-#lgxmdGi*BKe*b}RD*IZr@P zyl~U06>bSnM`1i^>#-YEsI{f{@7&HFd7=rQ`tk+Jnnss9s59q*a%1X*YU<{yMec#P zs1rfERz4C{PaeuqIW+0Ve)Z-Q9nN;`&J^+FsBPd@3R8s|rusX3I;n+}$4QaSr{ZG~ z9*(h9B4?`eu;VQSRo*H6K$3L=K99nn0Fe0PQcfoGj1xyD6!mDzsYYZ3{=(xxPt)~1qfklS52AHvbVPcz7P->q`?c1g5 z#?>4`=ys8%yk@a_f05bf%K7^DuZyl!rsGZNvfs*5{Rs6MwM)6kcHWD!wwDqSvcrxSbUMC{eTT9ox2T+sTe?+qP}n zPIheDwr%X#c5?HaQ+2BDTkpNMsz1zh)#_REVa@8P?*DIrkwqeiW z+Do`2Jju-nRf5q))2XM5va1lSijS}qm0fPTb}Hs{KhOpuvc%2hq#ED_0S{XOtrV}L zs!()7)Ss4eqYq_8wWYKOc?H|VanT3 z8SnY0d(6aIB8j`0hFFg@;Rvp#!_0Bg=d0ARWm|e(o%I;qj~QXUy>2$?C4^;nQ%0L= zdG8wkjk6@xkI6&~tcPE*LR0FiTxmV;qJ&ySnvk7x!=@N4kz~n0Dv^r7B7YR(pgYb; zMFUChf1g3)>z*q~Y1dY3=UJ>hWl)`NiVlAKQIi;}v z>{D9IR3qnZf9$?5C)u6S(84MdsI5$?AJ_%6ET7@>`dL1GYLAOlFcsbLM;zvDWI~O| z*yzFbo}EF3gW6eN4L^oQz;@+Y+Iic)-mPAW4?zl@sVUM>&t*>kxk(EihG3?=qQUBD z@kp6imF2dST8Bn<3{q&;2r4#f#noYn%YV}ahthPR-w)VN80muXVI4j1V|MJQp+`uS z1}w&H77R`sGX*&G4mC0$?_VOIX|>|%C|4^Sh>&hO(SPBlkc!gF!(t^g0@{fwv`(ib zhv#W?hiOM^3T!N(-YUg`vgTP9Z#_R6u5dYKuyJu`Q zKQ&mS!!W!Q?(MtA`gSCRbEDKzSCVMgoGPh}n~Rjrtu^!($jy57leu~YlG*WxZG$QDaY-F zqbvDyO5;+l(LpF#;_P7RuV>MBQgji>xv#+b(E^dGslx8#KKHLQbrkNaZ_2tPBBH3{qjI=86mY$wTv7@tlJK)10-axd4}P zL?3KZ()aVDMY?7$5RVpo`Z=`>8qXg8u4(V40qmIJQyW$3WNpH92M47AQ?9d!L^yD_ z^mFg-21O@y$+c+bP&c&gfUbpf3P~M;KrzrolEhfMnem>F;n0d-b%*=%sSWA$Q@6qc zm|8;nLhzyV#a8URaa<#2a1pcK+3Nsj5&fp1u}L$#uKv7k-H-Fvi`^ZqZnvMf-7oznFEB9FNQ1qA|CdO<%9?_Nanpdu#XK>!vuO9~B`YHO$ zZDoynfiG#WzP7xHFUnHn)8w-MA3QZXFMG=;gkE_4z8_ zrR(xtUvjSTZ0H|1#pe+_+y1@uj$mOjOcz=A~vZ@cDI} zYztmp&jc~F4Xy$=rh;t9y@c-bPG2$tdglrxWvj;F0|FWkF!-< zA)siZ09>|W*%2bFYDA+2YqW5D5iJ(?bjiaB5Ii_DbG7ego1n5b3r!K(u2 z6wT@4;yc8_00jM)!z^#92WLjC$+hWx$ieXuv}yEXjSA`As!h$V$p>*Ltq)#9EUn zd&DcJ%+t0-S@d}843D`EKlcW_{Fe2*t}{sv{1g3;NKT!1T&<^YEXz*=w&9JpJhVWt z%Bh`HRf*J?(2$L&&DJF^h}n*R3l2P>D5gaH9E_OZ6a6if6SO%K>2@QOYcWMpp1!{0 z?_}~~c0P@orNnh+P3MkqT`8Gb?Yt(51s`+^_Xmoo2u*uWx*)<&c#583htTumWl$_?iP)i z%1*K4iON{t6jlKu)aG)Tv)@tOig3Q#nD1?fTGf}~!w9cywsG`rd@)&CU!u+vAeJVM z^pC#K^1|NGhY{?cy)IzC)c@4LJC`>L?==tG$MACFJ;oW zjPO-YsW0TO8S|U10088>#l+;Yo*_=pAcyPq31hW!@s`kAIVgHs&#u)&v6*94Y;4cY zm<5t@I%q8bDBl5}q7RA>nId?`V^I}$92G(wfyt5A!6l-xs59I)X?>d+xpe^ZUGuLK zoMdCatrwwQT}@pvZm1P-ISE+e90|^i;srNXGG(jOx?YW4_$su#q|0=?kJEd7o5zw6T#f@!B746!^~>CB^rNb|>-zdmrNB0@5;z~G0;)(RuoCB>w#@BK3WJdKuei58U*7yc+ zll`xre2T`)tV=f_u2>NT-*+-8L!NVJ_ySAvkB41QccBk8zYF-@pZ*&ke?R>1Blzz< zFTX3hZ9u~@|I&Z(MG29@4D5dL^Cwki*;$xRujXJ(OsQsQ2IGclR+u&)RY&7kS40WI z;L8$r|7QXc+wNt{1lH2jE!=`^;+D7&gsMaaunELVG{PC!JV2U@W!IJj4pVJjpHMEXuL)-`h16B?jA^lzcrEHb3 z0_;FLK;DDaEi>kmRWmsvPDJ<}sVw)CU>qj5LMc`UdNEE&D_L#i->eSupH}}0UteZE z3rve)2_VvhjCP6D-&!&T{ z0G8bu-IVu7k0*Nsra=#MBnscJ{y0gTjxF_&{C(hi0L!m~y^It0x&0F}_$e~9dMksN z_Z>aR0zH<%s$vGZ@|6$@xm!f*PrDkUMPiqUqp033YoM-PN((fZg&gD(1$UhLj;J$} z6{X}SDW)YWYZ7>PnVfW!2gjLky!TVYIx1K+QOjZibufi2`&wxvc zF=dL|q0MBG=fcpq`zW^d1`6)XmFoY>G5ym=akzi(JOb%*g!9u=n zS1a3)4)-0NT}BT1wblH1B5QAg(;V9qr5-O_j=U#1~h#%)vouH_~IvT91HV|D?2lkL1XmL5a3KV|o=%84TD0tDir8Z^?;V%=}QW5emGdC-OE(V}N ze?$Vbi4Mk>6%|2>2_{LGmGLkfQd9sqE#NX7*dK@;t>ZiyWEvO17-1pUB`e?su-R;J z(2xWDFiR$~E1)LJK70>dW!q)eEskp#(oDL}~B`W{TZp zE+P$_<9JtBjQ|Dfxlz{y`y;}-&6R#Ev|N9y8%L#=VaQ_0AmY0t4nSj}8e&Li?IfuR zIP}-sfU1ZJe60mRv2e?>1$ARVhz3+fM!u;f|Cf5OezvaJP_^h}&VXP(5eT~0ORK70 zQC0)z`HUl{F)hqiqEX#|jkqY}6LX{bi=K12!kFU`*`VqqY)I!#rl7cu$y1(vwOKmq z(rR9&q`fyY$GmChX>I5`bWh%s2-$eK)!)&-JDuxdA}S2Vt2PlRLVj?z2jI_T^^r83 ze}qgP^zdmZGbfp5v8vnRGf^X;(c|XM&v5iD;H=~*Kv`yeFOW`rox+Z16MHWKiO>CQ z;&_ZE3-zW*YJ%(i?S?*HAJ7G(OH0=J=u1&XJ)?8bMLv>c)J5NyIq0P8*f#7GH0B<5 z2`Y1qI8#NuLYl2E^ypE)rc2a0XbYpbrVKra+?zRQRd{qo?A#Wy<#*VmvHXbCNDIFr z8x)`57_!XUh$(CmBbL2u4?krAXVEiO9X`TQXfI254j)s!TO-5T96sPl;E=;%3m*Vu zTq6KF3GWq!hyMWM!x)Dp-MO$Vr=@LH<>h~2_#-Oo zW~u}QZyMKZUWNsb_bV-Ar8w$anqSwPY<5uAhIYO-27s}v(y?ix4X_IUTDT2%#wj#f zaSca39k3K{@#T|4ZSn%gOr1I3CXU*tyIWdG&0nIsXTb=4+^_>8Ea9$7rUe_uC__%} z#KK4ce6ey)Cb1KqXK0b_k#S;TwQ@mnG(k@bT}(Nk#%jPoO%Dl{gp^>!rf>11Gkqq1 z7a(6euRW`|{-}ZPYitRU*~x3{RST83Y7^=jLWjr`2DD^gx@^pOv>%=2OHD|6x!L(R z+m^fDDPQrc>@$Y?j8}5DImdr3A06=#E6O&p`!TMzU~jU4 z2S=1q5-jY9(h$|^%R=?G_383mP9T%QqLCT~pWr zjszGyIf^6Ud((Pz8AM|93x*g*{_EpnHkU7HFnCI5gl@guor#(hkvD_qnt{{m%c8P^ zX3|bK-Kca^jJ0o50_QRl_a7=mieGbowsYKA!S)Lj=e+$>O!gA$tdP9kJ`M|54yE-= z5l;5raKy<5`hlROCL3QS z+j=z}Qe%8p-c%Zw2teqi@y#^p*bjs9B5kZL$(J|+B@#uLE<-2x*1nN_pFWWd)WY8R ze*r;+((m+{)S}k(cR*!}7bapTaI2kn%LvfIDl=LVCF}6P7E$3+&DF1>$tWJwnIr<&F=PD`_*j6zT)fSc2)XcXo#ODd_DB8K!W!`q}OrKgKYK2nHGa64;84Ou# z6zIja)}+%AJ5E&S`mJMNs>FCUY*@S+sw>uFVn9VItng@LQca1nPo_o+`TAVR?9A{w~{5=i#yOrZOW zw-|wCMy*53Rj&m=wBVp|RLF7SdFyWb-62U}+bWxS#^#r}V&4j_%VTcwQndsmt8Z6nCueB>f+0&PShb9JwE zbUQvAg~Iil_X=tHHlcQve&IbhzD+$3tjJmEmHrD2O4ia(IaE`aq{fA#(k)-@=ob`+pVMmvDde;va66`AkH<1?a@j7JDY7>S6)hrvcW{tK;y?b z&X{GTERzbQhny@vE3v>v2glE`^KE&Fy9T0314Yw%T$nE!9N39n#mv>+_*ZLppWbg@ zc9@|#xoY?_6tg%Hkaz31clJNwFi&IdF7hIX;$DOYV&A8RgpIVD%s7q#42e$<~UecN>zf+q&zUOL|;$YtgWag$b8|sR7NxyW7zD%W4p%)9t z?iW^=u`n&2t~IipTE>QE62ysj6VCm{57MNHid&`Bi4t3A8~S5FD0J+a3H1PeILm68 z_i4@!Jr}}gjvWm!m2gM;cJHT2Bo#+>(52Ygjgz8WUAj{P9Ixpl{3PC|b$nXI{mKa+ z&(BBZ#bku{bZCq+13LFa+xhxWGVFf_Som1Zxy$ z_v@n#PanP9gKcXl{^O!r!>N~vU}_BJ`HXSsLWwR2t?5?cOW0+YSI(obz zb(;k_W&nCJI7RPAeh|e*FSGd$%0#=jFAt?zj>oPFb=LEDxAmZ3$2dysrxNwWx;(&D zg;#fSe{7f5O^xvO0{YkgHi_iha-p)S{C9#u&YnzATmcq@yN#97lpd4o!Pt zLn>%?k)iF@MNM*)*T)_&#lD3_pagEFM-;av;E1TWfCl}n>yPL3YMIO4-hnD*!GSLH zU}o9a=n4>iD+&iSRj|05papJ>R(yYH5x?A5Ml+;t7FX-XzVuAkcTL!XvAj##;Qf%R z*Xm?YiP{;Fd{|Fr+P%2QJiWbOVu)wAyl{ z1iTR?-FY}pXH`@ai|oAW$(tgF8R&zJbqMs|0tUKf9$gxAb+yQBh^s{8cZNWUxzDlO zE;L78s76+(gR38R$timo@(bdO1qe`63IW1HE7=V2>RfHDtDD`~JWq<9UEXHXsjsFe z%P1Lm)aRr<5fZu=-vIokmJ7xwjFMN+P)~x~&nx-Gi=Q;l`_0!H3eA4&(1=l&8)4y% zJ_3}@mBVTBQMICkTy5Y8q=L=66Vji)YwEda7Y}WQ#=qa}m`!MVGDe#BqdBkTEfvdI zX{cFTgl5xA)&E+xpdvA|r-K%vHJbB#K@ugYl7x1*pui*LBA2Xk>nX>0jYY&eF|HI~ zGE6Nv)sb!?K3r+zYovw{q9&_FE7yw?O`g22l4-`>jyZ8_A~>CB+aA3`mL`;k{iYq7 zrJ!xbd3KbJ6OQ&zudHKP9ZK*5Z_8TNigscuPIRxxcpR9J&X#&`t%>fLswKbfyN;#5 za$i)ZZjqv^?zyt-z%Pe4~NrK1c`OpW@r$OO;v87dmeIGQ%H-zghcHX6nv z4bYBN?K(f9dXYAVa^WN(M|DF5+`AfyI&;v@SPZKZ?SdILJyXUz-xM8CB8`B{qNWc- zqbez*u)T}UDoE9|j^!37jXg&GV;TH566sO{+Q)KQiYG2bGbZ0GU#&&kH9FmXO`TJD zEk(Ol;=Plf7L%k4rIpxiBB|>Np3W|Zr$)a6$H~$r_5Ty#ojv6-4NIuD#umqi=Ao3< zV{1T12N_HESdKYM0}Q0u#X}f4F!gQmzikFF*yOuuxDYVy*JC-R2-{w6ImYCt**H)q zJ?$*4I>Y3bdF}igw_W_iwS6kj)c1G7PWgrz{L`FHzf*~F>7L4SO`!|?jlxIm?P1;~ zm&PvQrSbc;x-M<=$&hDX`lj~CZ>H^44}te>Nx;_M_n69C@gMsg@ZVOPxZFE=Q<&KN z>&DjljVX0J|LY)nXj}NSXht#47mgYv$x%7>Q0gh+s%{^nLA*P$@;o)m0?3FR;a6PVD zhF?aX>~kZG_NSV6B*($LrR{+&5VQHzi5%3{u<$%2{LmT=_l@nY8;3mLwxw|b=Q5D+ z03@7$319=612F?(r4uqZBQ^>gegbK%0 zKM-J$VRt%Fg0i#+wp7J5p2XD~V~pb!bS$&;IAF+-m44nBczW0>RcT=aiP^mHt2EnrLa{~ z{&O|xog}#3=O3h9<=BKn^nJ#&X}fi z0jk`!Dn+Id9`rJ@!o=z^#{260q+^N;owF~;(EE;Af$cvis6%zJJ0jYNjSn!zH}~ZvzK}6Kz+eA81|6$Zs40^Fy;G;CvBTSz=PnY zuVD{I`{)e4)o5MP<9vfk$1w=Q;*S&OGaK@{8>{7r~w^e8!A7rT( zY_CWfaAdIfU#4W|v8LSHOBp898*~P?BH6l;Jq0{5c-#_4b=?6Cs>Ahy1(=%4$DWUj zh`yOB$G^IXey6qbmpXJde@P&UX>oODeDZoJ4k!1iqSd2^-6t0ROXsD;O80^D`~F&n zyZg}T>tJJ5=OLt*dBygR-(Ch&NtkfcjfK`aXl=I!^^5t{w#NHWsfDBVHmAmjSgUJy zbX-lU6*K6gn+@C$==HmcwmXx^(DrpZV3P_|bFBUJ_WBWZ&b+vNkUd_db$dM8<$GsC zeC};aV3KK!JwN89oa3SIHZbD?ekxG$cdIt|svj;5=!9ZE4f?_|L~>jf$i(P>vU>2C zZoQlTJ;k?;bLN#qVsDNIf$5SS!(+X_CFP=vi`yi_maMJ-) zqu%gQzq2j=ET`S+9m$g@tLwCfukFkmXt=3at%G|fxXIZ>g;TL27{2D%?<1O~dY1SZ zt;18ogdK)9C-TJ$O9om3y^_XN#L`wT+R@u5wWhW&$W*IB>3Ux+$R$hQ?)}h%K{Ct{ zq;q*BEKD;E^Bu(#Q^d&q-hPQ9Ah|D`Iv|DzuJa;9v&{yjHMgZ!tQp^Tr}pfs1+Sj< zBb3=+t4N)KTKYe#BJG>k7LkmOq8J6sMq<4zq!_S?h)VIC@K?!;Laa|5o34@;1&MDm z%M^c8sJQ&Wo;8rz0m+eu1v;8bf(3-VVx0-mZ2}%3GGXknx|na#k4dW%wpE7qb&y%B zT{pa9A==-Wn@+Di)U{^OeRqBZ`RpbdT4S7e-5blp5E8HvVG|=Q-oORU;uC@jI?BX? zkM8$xhse?hKt?jZRn>pLN3#@Zy8l zHz3p3bP)PDz3)js=O6f=JK(P``+DDd@I5d1KjS(0 z9v)!Mnfwp~Fs;c5cE{5D3EY_^y#TC$Z4joSc^+XzXythi(LTUY9x>c{lS!=F1ky$v zusbWUFWzReUM-EyU;os0o^xML)ppRaXIodgZPbze=bV{Lb(nvl83Pt48sreF^@RLz zT}|Oxox;i`LIGgY60aFpD4hBpe|^&LPUv&H0es+3AI;_-k$HSheb`#ZcyGd-Cbxc? z)M{VywMbZAu)>bW%uENfn811Q$agTv%pf`_$c`lniPIAqo<#*vITKmpkr*WO^XfGB z$oGvWwl$-I_maHd8c~%t+GJ1KW_(w2B5W=ri#N*YYy$dkc}vvRjd*xL!X3JN_D_rs z7@Fz12krC|d^8gq1c<2pQ%lv!@jv>|;~$Kp8x9!>;^TwPyoA(GD1G6{*NPxk1kH%< zJ(1BB9>MbLyG0ZnX(rA8IkLlTvHAaKjCpT8suOYJD zgdu9c29~|tu~Dp&*}aE^4SwqLC9Txg6)NE`svtGEsa;sSFBX?~+2yTm(;j}(`X!m- zLE_IFwQ?LbY;5`D0CE8(B4Ko>cmL8-5;ld$A6bf=2#p`0$dUmdWo_*YFQ+(V10CIa z_Sqs(BHh_^REi6*Ic)f#71V6edcrH`xF_;FddLtdP8EMEz@Q*KCl*%>BtH{?PF@k| zEmf3BmOfUAxscW%32CKMnobQAp0I$yJ021L*K<5Tg6QJ$DONe0mad{wlIo63zaDrr ztb%gQgQ5}8#sMk3Sz6kENi`rVU?rRw2h9P2&RGBYwd)h~=;YyVry@M9qSCn%mI#IiU$pXBgZ2EW50hfV|o?I)St5ptYJ@ zY4VpB4xRL77JL)zxLnG_dn$pn-i8SpzXI^jmqzPrQu4PuG>sk&ygXj5oU_D0**@EA`(%O2o=$ndCd9?~>N+0&mK7`#1@sJiu z25FVf*m|F=zj>@fi5ZJYeuvDQD9M?w0J1@kB*^|Kv!SB?eL{Wgm2WUAk)KEfPMNz0 zryUXyJE1MF@7?{~@yO0$HF$AmOwLu$+Ium$Gz?;NPL&Y1okkV_F}RJYr3(Ps_4D;{ zpI4Z&WpD2jO!8|^+71|u2hGZFLqm7W5mUgFNA}6$Wq%I0Ak)N(0i|zJHSkZ5FeUFb z#fC8K_ss+ve??50>9N+P6{}*V5kk;56B)SenZvyL20>3i)tWl@skQi^0iju0A)}PM z3!!Y_xQ&{7WTQ)Qv>7aH~+pCG5%#j3l(=EKO?y=3;O(J9Q|8&|>_J_F8%txKv(%hinqY6?ZuU+f2!lmO$4( zX3h0ub!&)Yk39h^k(bOe&%LgN3sbhT97g~~qPLLXgBbSL###Uu+agVGFT|yl?E~n- zj`4Fd8xQ2EIFj%68p}vE<`}hOoc89P9^a1`H~Arww(Y?b6Z))Z%~3S3IQBf7x_Tpc zc)sraLOcBhv4q(GT}cyIQvv;b@szV*06I_5L-rh!+Xqf{$^3w}01@VMM?sKD7Qp0^ zTnoPm)~iqj)5dl~XJPdxEozEN^s_>V(!`UXUXy?fM7%$;tm`x_FteuS`De7{?_Ly{l{%w3K(~66h#Nws zWeqs{sf z_^UM(_o+3Kp2bg4aVW-{V=Fi{;(MgqW=m5)A{VE_W=}bZXmuNajsG(| z7d{^iO9Z8ss4ac2P9JZkS}kwpS*l>?t3j;3NZkder6l!=Hpj*4S;p@2o#CQ)%h#AFW$;Z6hq1XZxOl*w;nX{m#$>*!lE1P~kh;@Rp!%a<1?O`8*}ok-{tp=UzN!xsqX%gS{tvVPs`~Zmj238?5U% zvH^G~6tEQE4J1WL(*e96>UepDK-S+MArDA~+_ph5^{>Eu#0?`3*d_nArsxBcAS1e^ z9zr7d>k2Rw!7nHm@T^S@;o9D=(lkb%E`!P~7DH$h*?--oKr$!jsePr|va$7qcN@GQ z5m1RT&p}hzDvm!iP-vfCh>K_XFRV005E&c|)jkNo8s(Tz9T^H+7L=tn7V(*I0j&eZ zpkdA;q8>_qkD$IkWMewtwk$LyGZ1}(AX(%u20q9b72MZvN@E8KY|;M`M=}kMn0s2S zxfOaMG^mfnI_RH8r^72ZQ!MTsoQnE4eU57YMn}OtSikW-f%VNf&L@?k*snr6=oEfh zNShf>u4XVQ)X%oGO4s}3grC$erRX$Hf8mZJ+*yNE*tKy`ahNk%i`j8dOcEAlwXGjG z?mrOx^vS`9-(Tf!V8+ZCq5=yQ&gC+*y|sxnshcmXDBwQg9C(oH` z&{yUCmNtRlKF@#!fruIw1S6!=)LImZv2tt@nK65>@Xzp&5M~K&Dk^IK&-~#+EuGkTx zVmVnKRJiNquVbn0ogu_AQ-gBk5{X^yLOIWSPCtQiDBwAXx)z)gk78@2pq#9C{4`gx z^{N(?Ge2(GH23-&sI5PxX(8ZFvdU^1oeG-pO~qD8Nc?Hn zxqu>!Pq4t9;4rX`&?^%--C!kqEox#BLZqS8^oomN^%cJHW}@XcU;*;8^puG5$Y{O{Fz(9l^;P2Nk7=hIH5 zT5W^nXi4)BOGxS}narAH!;$LgxPC!<-ORuTAG>%4jEN{f7Q$8wFtxy?g`-Qdoi$Ug zm^G?-sNm3qYlg;NTVjsrG90{mvA}}}S_8f7!5E0AM^DmA?tR5(&X$nQDy$Q985|5Y z7(P@#Qt<&c-6g`n=~&pFV_wiI5~!l7Htn`6Z0`fGXqW8i#!NBE?bwE_A7JV4$8Y-G zWhRCNO4|U4&siY=Znn*9WwhJ$oTXB-fSzsV#sl|;v*{(?V1@`?EDQ$vI(yuAEYrHp z95*3>6hd!Q$p%4VLgo)l8;Wg2I*K{EKV)P}jQq1PU=Vgfok|cJpsIL6lyyEhnyd`ixV_za&KPSb;wAMKFQhjZU)W=3X34o`p!L$S)LVyBpYZ!7?S4&lxI|xdz@X^!D+}AEk{AKRx&>>u_bq@5=W~Vm`h&*psTj; z4ZRZ6flmd>7A)R$A;yQtCghCv63XDfeqV*icqiDdx4OkSvLUi@L=`zzGDN4ilQOvE zm4$>x#Y>yU*$^nsv7!nOGh;Nb88$=eaK2b6Ido_FBY39Jl-*VxMZgo&u~$BbFzIh7 z)jrGTfe9wfn4gj+CkjRC_><(AOLA&nbyvErIXiQpRtsilo^02dJX1(`JVy4I8vmtw`8b}=2y z&ll4{z!r+PAt4bsY1|5N#g2g~yGWd#aN;_8m_`2Be=BoRfO!0tHUG9bC#EQpDTLU9 zCsF!5WPwtz224Kn#)A}KJ(*A8G~bxxBeN1#Yahq+rl>3kf=%8emQRz4LJ>9N=^zkd zr#J67BVFe{i3p3>@<{ch7*2S>szkozgt1Vrtn@0#7Wh+97}*x9&X#E2V3cn9hyd5* zJS3mta4Z5j-yZFlAV}M94aw{*;ftR>7FQMY^ z9W`1nw*~tQ!-?cZec=#We60kmo50)HSETV-e+f{TntdQk9~tJID$$x%KQ5R_Rm-t1 z9(=GNUajg+AlV;A0Ahil;ILY0T2HK6QAt*MO7{1a6^Fqj3=lYyLkQODFBFO)SgVEt zl!Ex421{PaTtz$ejk8F&-7;c^+T7AScFraAFOCnXK6t^pv)!}N>;PEcNn_j2=c3$z zBMTBeX@sXAIrHASBl}Xs`;(A7bG7JtZ`uZvW_smFS_d#_ zLaTl0jQJR48%2RG%F~!l>a)#S?1y^3Q9HzAx;ab-bKGy+WFDHm)7Mm3dXM-i-dvGoB(A9*+_O8|*P)bWuB3A><8 z56V}0Vqi4TVt3Z5DDgOs8^<0bh4`e1P%U@g*72hz?{S*YY!GoI3=N%~OFMj+y@2ir-fo$TF&z`q32<8$}QwHh`(%%>*Hh=;zsOoqNZB{z06 zt$duSYvWhcpln+e?K`W(HVc4S#a55)v4PmdpRr1EYr3~6rf}D=VyB|?e^MoObCr+W z0eW&8G=h&sW>r&>CU_XUj_A{5H*$iet2#<_~?5e#!L@)%Ruf+qXG6__ zvq)dd8e}Hrf*RlTP<_9Jo8KamHRaqRdhKGHTo=d-BVRmlTc=FyButW?a_p7zza;cc zw}UaeAscU{`=`Q|N2ZV?^oyuCp~wk+z14hJR7@pZ`}dyK%2BQiZtqh+AOevn|7ls# zFQM-A@U@~Fd-boVLmxF+R@ESaTMiRyf(Iuq&6-fZIP|X)qeVrb`(KKY5@dl(!|f^I zZ5EE65A;&2e_1RaAtXR0kTQMR4XFXD+o3_?%aObF*e^q0H1)-1^;Ir*$FK`~OG)_U+C9<^$=63bT%gL>4`{5_cX6$zt3t{?W|#Hd5)2c#4rc zG?pt-yN;FIx8h5tirTeag1#c{z3L%su&|`(Fbu(Kt~V_hA-zx%M$%Nexh}tO&Exa+ zz8QZ$-r-ep!ygMN8?=`lDcKx8O|8*PkeRTU-)fcHCT?@-6St?Rhh0Sq-$9T6QM!IY zJOTq1J}bXzGgyKVIs}M)W(hH~VCeYfy<(Ec98LYKH8ppC@g`rMBwkEs`D12Iz!4L7 zPv)g)7~0`e^vOIR@y0H^ZP&1nbCn%YM+-HSL#L0eGp{eZ9lEVPp0xs>AIy|_;6S5v z-jo8d$s3N$UOOdOzm6%O^baojzJs0#W=8$QZd7^uZbNr=>BFaZ>C$;u^1XMt{%cWY zmy!*x`0+A&^hgTD`C{AP0s}2Grzgt8escWKKOMZ)H2VHY1cujDnBG2gl8}m>TNq)l zz;`*U-)yCW{#L1WwX+=u0U@&)kcJ!~kU4YYW9wzfu#p)6kl=FVp5b#!{RGrIHO(o4 zzK_|cyEj+gjQrI3a&GD8!mB*6kvY`;ZopRuzr$Ohe*LUhVD8Bq&bo5gwDdMOsL_Wp1xV@W>#+XyP?exh@ixk#bNvH=pP?ecW}wmUOh9kC9D-oz5$m7( zFA_V`=Ybpa%t(9^u{X!=;y^fQ`Y2E5o+Q7CkVd2J=9L{&lGY8ve|0@p)rYlU|BQRB zw!OInu3tn$Ye3}cpEjX8`0Z!6XO!?0r_D{)U_o1Il@&twA%lG~l<(%%-&URzx#Tjz zv)R$R`I1sQ<5iJLAZz}FnjGV!qJ6b>&;Ug;HXBTaQqMA4oCAJPe)n3}qla}66I~Xg zglh|Q%c#{2SCd6*(^cX7F)*nwhc_mexsGBf-0ai+hnq4d0%K?(nqb-;iU?N{mJMEl{GmvZFpf&k_>iQckhAE#$R-#kF7*A80+ z6T*Y=ttPZN33O?-o;-CR*mAe9p=!}-wW)yWtkI%-&aXK}cQJ+$@gwIx6n?b($KonZ z#bn4T2ry1t&x2Smrk9eQxH)&3Z7dXYMT164#pJCAE4JYSGu8RE1nrBug_%#d@Rho? zTrpNR>x6x}qdUyb%*boD&vM3WzX^HgDE%on;x+L5_A%NG<^Mt7kVR+nsl<8gXJ38n z`M5ehqoAoKx8Gh>OiD%QO5g=WlQA}gu}wob48h&EUER)Lr8V`csXwNr7$V}Y2)7Xv zp5E%H2*XUHHy`qxIk{*cgy)CsN_Knx({)*Ka8Ma65#EI@@HSgnrTj^<#fEErym!LYJ|e)~BVs)~j4 z1Pb091yx1C;FbylxIVyco*-AHOgp%6-H;8=bf`osLI+9;+Q|Y$Z>S)OdY9}c>KeJ2`8@?QTh+$QJ%~I;c@lA_`;t58 z-CVN%5dXM^e>8ewD_SyeL}JLBdf{%}up4-PJ6)>y)?C#z{aQBW-u43>26fdmop!#OUhg^O2J4Pq`MDvSk5n~c3ia|NR6u;{F;@Q0iJ z<(&7G;{D)TFxW_4A0o{H@yCRQk8jIhSXipB!iM=O?0N$aqSc46VNcXqWwor@b*J8o z1e9(nP`X}iC~e9hl7Z4z5(k$gd_y7p1BLM4t2W`cB*G7rpvcP+oMjiOnPc{kT?-WI zA6GG|c4XLBnnsgB=-}O4;cod%g23(9UPw1!`$5lg2VT_6iv7Ea^jXc7KCK{FZP?*l z{7+K+mu0|w8JPAYTg#th7-t9(ZOLp)rq}13yUGU2!nT>W>%>&X+&!jU?sy?6nQ8%7 z;rJ^G#}})}ak}F)b*t$eF|poLNdMg;q@T~JY0ar}JOOz(UuY(@(A-gIzfyqqFeRFE z@*A)I9EtqjSIEC!ko>Lw^XIG1oCn4@j$%9zOZwZJj$^rJ-QJ~jEUte$7T1nlT3(B( z%D!u{MlnFcbuu>J$N!>`|0lnODfv97wqey6&uWl&tOnzO2LUF>pl8Y5W;JmpwPx3n zoN4h#Fu1lG;#c^BDz|Hk;#}YhtWb9$7Ax2b`!2p0YRA(s4vix)G2C%L%wR-*$Iu3536$h^Fff9J6Aml|me|;QdgM zOB*`uO5Z0#2ide?VTM!~Tik<-9kwcm{bsKpx=eeu!%MU=vMqnI@aqbk{loO5_rULWI)}%glpRAOcMq1}$MsxK6+8LhI2N(rh^eL0V~^unzl?)JwSy91JavB&qwtnRu6YF!tETpy{gziJn-}Ie__Fz{laX(r7l`<{= zYjGTr+xIcMUlAo-tHxm!jeuc6sYI!W1b6)Ag@jWkt0Abr%$N3{?3aSRMZaB4)iHD# z!9wa%B2^%0ju{oFNqAX@w$ke-f2hht_;*->Q4?(`m$4HbQ!Wt3ZfnxOnch?t%G77- z=yZmQI<`V68NGJJuuG`6JE3msAvQT8=wUTZ{gZ~0?O%S>nhKOe&Fbt?$803V5Q3;g zN&h-DpvFuf1CbO;n_)fmkuImJ8a5M(RC)#E(@(dT6Dazr|FVpAVq$1IAgqryAL3a#Liz5%OZLttpEF1NUDPY=v1ATjpjGOlq~^G~gt> z7c0M*0;1g6bq$cRqRljX%}DLROpTNqamq-C^6F{_F>B?E!AGL>ZH1_3%%a9O`zN-q zO6Jle&Exaha6Ut`n`!-PNM8yrAbG1qN}Vu%OB=kYZ>PPYl%-|Ej@%3_v&7Qs;p5QK zNDp22^+S+`F>V*NESn0ubrLOScp2_qmA)`|C2_NHg+cT_!H>Rq^{x5Pro|*iS5T!Wtuak%lFjZ|uXf6QiM_rVU#J!xGS%SUjJt#nGGxdSW+-XW z-oMnSQzI|$IL_n1+7)nMB3|W5aUe~csd3UIE$QV|&xwh6zrTDuF-UcKsgvyKdS5m# O{r>|ao(6FPHv|BUx^cb$ diff --git a/test/e2e/arrayMaxMinItems.ts b/test/e2e/arrayMaxMinItems.ts index 65d3f18f..dba6743a 100644 --- a/test/e2e/arrayMaxMinItems.ts +++ b/test/e2e/arrayMaxMinItems.ts @@ -10,7 +10,6 @@ export const input = { items: { type: 'string' }, - description: 'minItems = 3', minItems: 3 }, withMaxItems: { @@ -18,7 +17,6 @@ export const input = { items: { type: 'string' }, - description: 'maxItems = 3', maxItems: 3 }, withMinMaxItems: { @@ -26,7 +24,6 @@ export const input = { items: { type: 'string' }, - description: 'minItems = 3, maxItems = 8', minItems: 3, maxItems: 8 }, @@ -35,7 +32,6 @@ export const input = { items: { type: 'string' }, - description: 'maxItems = 0', maxItems: 0 }, withMinItems0: { @@ -43,7 +39,6 @@ export const input = { items: { type: 'string' }, - description: 'minItems = 0', minItems: 0 }, withMinMaxItems0: { @@ -51,7 +46,6 @@ export const input = { items: { type: 'string' }, - description: 'minItems = 0, maxItems = 0', minItems: 0, maxItems: 0 } @@ -63,33 +57,27 @@ export const input = { properties: { withMinItems: { type: 'array', - description: 'minItems = 3', minItems: 3 }, withMaxItems: { type: 'array', - description: 'maxItems = 3', maxItems: 3 }, withMinMaxItems: { type: 'array', - description: 'minItems = 3, maxItems = 8', minItems: 3, maxItems: 8 }, withMaxItems0: { type: 'array', - description: 'maxItems = 0', maxItems: 0 }, withMinItems0: { type: 'array', - description: 'minItems = 0', minItems: 0 }, withMinMaxItems0: { type: 'array', - description: 'minItems = 0, maxItems = 0', minItems: 0, maxItems: 0 } @@ -102,64 +90,54 @@ export const input = { withMinItemsLessThanItemLength: { type: 'array', items: [{enum: [1]}, {enum: [2]}, {enum: [3]}, {enum: [4]}, {enum: [5]}, {enum: [6]}], - description: 'minItems = 2', minItems: 2 }, withMinItemsGreaterThanItemLength: { type: 'array', items: [{enum: [1]}, {enum: [2]}, {enum: [3]}, {enum: [4]}, {enum: [5]}, {enum: [6]}], - description: 'minItems = 8', minItems: 8 }, withMaxItemsLessThanItemLength: { type: 'array', items: [{enum: [1]}, {enum: [2]}, {enum: [3]}, {enum: [4]}, {enum: [5]}, {enum: [6]}], - description: 'maxItems = 2', maxItems: 2 }, withMaxItemsGreaterThanItemLength: { type: 'array', items: [{enum: [1]}, {enum: [2]}, {enum: [3]}, {enum: [4]}, {enum: [5]}, {enum: [6]}], - description: 'maxItems = 8', maxItems: 8 }, withMinItemsLessThanItemLength_and_MaxItemsGreaterThanItemLength: { type: 'array', items: [{enum: [1]}, {enum: [2]}, {enum: [3]}, {enum: [4]}, {enum: [5]}, {enum: [6]}], - description: 'minItems = 4, maxItems = 8', minItems: 4, maxItems: 8 }, withMinItemsLessThanItemLength_and_MaxItemsLessThanItemLength: { type: 'array', items: [{enum: [1]}, {enum: [2]}, {enum: [3]}, {enum: [4]}, {enum: [5]}, {enum: [6]}], - description: 'minItems = 2, maxItems = 4', minItems: 2, maxItems: 4 }, withMinItemsGreaterThanItemLength_and_MaxItemsGreaterThanItemLength: { type: 'array', items: [{enum: [1]}, {enum: [2]}, {enum: [3]}, {enum: [4]}, {enum: [5]}, {enum: [6]}], - description: 'minItems = 8, maxItems = 10', minItems: 8, maxItems: 10 }, withMaxItems0: { type: 'array', items: [{enum: [1]}, {enum: [2]}, {enum: [3]}, {enum: [4]}, {enum: [5]}, {enum: [6]}], - description: 'maxItems = 0', maxItems: 0 }, withMinItems0: { type: 'array', items: [{enum: [1]}, {enum: [2]}, {enum: [3]}, {enum: [4]}, {enum: [5]}, {enum: [6]}], - description: 'minItems = 0', minItems: 0 }, withMinMaxItems0: { type: 'array', items: [{enum: [1]}, {enum: [2]}, {enum: [3]}, {enum: [4]}, {enum: [5]}, {enum: [6]}], - description: 'minItems = 0, maxItems = 0', minItems: 0, maxItems: 0 } diff --git a/test/e2e/options.arrayIgnoreMaxMinItems.ts b/test/e2e/options.arrayIgnoreMaxMinItems.ts index 51f56cb8..f75c79cc 100644 --- a/test/e2e/options.arrayIgnoreMaxMinItems.ts +++ b/test/e2e/options.arrayIgnoreMaxMinItems.ts @@ -10,7 +10,6 @@ export const input = { items: { type: 'string' }, - description: 'minItems = 3', minItems: 3 }, withMaxItems: { @@ -18,7 +17,6 @@ export const input = { items: { type: 'string' }, - description: 'maxItems = 3', maxItems: 3 }, withMinMaxItems: { @@ -26,7 +24,6 @@ export const input = { items: { type: 'string' }, - description: 'minItems = 3, maxItems = 8', minItems: 3, maxItems: 8 }, @@ -35,7 +32,6 @@ export const input = { items: { type: 'string' }, - description: 'maxItems = 0', maxItems: 0 }, withMinItems0: { @@ -43,7 +39,6 @@ export const input = { items: { type: 'string' }, - description: 'minItems = 0', minItems: 0 }, withMinMaxItems0: { @@ -51,7 +46,6 @@ export const input = { items: { type: 'string' }, - description: 'minItems = 0, maxItems = 0', minItems: 0, maxItems: 0 } @@ -63,33 +57,27 @@ export const input = { properties: { withMinItems: { type: 'array', - description: 'minItems = 3', minItems: 3 }, withMaxItems: { type: 'array', - description: 'maxItems = 3', maxItems: 3 }, withMinMaxItems: { type: 'array', - description: 'minItems = 3, maxItems = 8', minItems: 3, maxItems: 8 }, withMaxItems0: { type: 'array', - description: 'maxItems = 0', maxItems: 0 }, withMinItems0: { type: 'array', - description: 'minItems = 0', minItems: 0 }, withMinMaxItems0: { type: 'array', - description: 'minItems = 0, maxItems = 0', minItems: 0, maxItems: 0 } @@ -102,64 +90,54 @@ export const input = { withMinItemsLessThanItemLength: { type: 'array', items: [{enum: [1]}, {enum: [2]}, {enum: [3]}, {enum: [4]}, {enum: [5]}, {enum: [6]}], - description: 'minItems = 2', minItems: 2 }, withMinItemsGreaterThanItemLength: { type: 'array', items: [{enum: [1]}, {enum: [2]}, {enum: [3]}, {enum: [4]}, {enum: [5]}, {enum: [6]}], - description: 'minItems = 8', minItems: 8 }, withMaxItemsLessThanItemLength: { type: 'array', items: [{enum: [1]}, {enum: [2]}, {enum: [3]}, {enum: [4]}, {enum: [5]}, {enum: [6]}], - description: 'maxItems = 2', maxItems: 2 }, withMaxItemsGreaterThanItemLength: { type: 'array', items: [{enum: [1]}, {enum: [2]}, {enum: [3]}, {enum: [4]}, {enum: [5]}, {enum: [6]}], - description: 'maxItems = 8', maxItems: 8 }, withMinItemsLessThanItemLength_and_MaxItemsGreaterThanItemLength: { type: 'array', items: [{enum: [1]}, {enum: [2]}, {enum: [3]}, {enum: [4]}, {enum: [5]}, {enum: [6]}], - description: 'minItems = 4, maxItems = 8', minItems: 4, maxItems: 8 }, withMinItemsLessThanItemLength_and_MaxItemsLessThanItemLength: { type: 'array', items: [{enum: [1]}, {enum: [2]}, {enum: [3]}, {enum: [4]}, {enum: [5]}, {enum: [6]}], - description: 'minItems = 2, maxItems = 4', minItems: 2, maxItems: 4 }, withMinItemsGreaterThanItemLength_and_MaxItemsGreaterThanItemLength: { type: 'array', items: [{enum: [1]}, {enum: [2]}, {enum: [3]}, {enum: [4]}, {enum: [5]}, {enum: [6]}], - description: 'minItems = 8, maxItems = 10', minItems: 8, maxItems: 10 }, withMaxItems0: { type: 'array', items: [{enum: [1]}, {enum: [2]}, {enum: [3]}, {enum: [4]}, {enum: [5]}, {enum: [6]}], - description: 'maxItems = 0', maxItems: 0 }, withMinItems0: { type: 'array', items: [{enum: [1]}, {enum: [2]}, {enum: [3]}, {enum: [4]}, {enum: [5]}, {enum: [6]}], - description: 'minItems = 0', minItems: 0 }, withMinMaxItems0: { type: 'array', items: [{enum: [1]}, {enum: [2]}, {enum: [3]}, {enum: [4]}, {enum: [5]}, {enum: [6]}], - description: 'minItems = 0, maxItems = 0', minItems: 0, maxItems: 0 } diff --git a/test/e2e/realWorld.awsQuicksight.ts b/test/e2e/realWorld.awsQuicksight.ts new file mode 100644 index 00000000..82611c6b --- /dev/null +++ b/test/e2e/realWorld.awsQuicksight.ts @@ -0,0 +1,843 @@ +// @see https://github.com/bcherny/json-schema-to-typescript/issues/438 +export const input = { + typeName: 'AWS::QuickSight::DataSet', + description: 'Definition of the AWS::QuickSight::DataSet Resource Type.', + definitions: { + CalculatedColumn: { + type: 'object', + description: '

A calculated column for a dataset.

', + properties: { + ColumnId: { + type: 'string', + maxLength: 64, + minLength: 1, + description: + '

A unique ID to identify a calculated column. During a dataset update, if the column ID\n of a calculated column matches that of an existing calculated column, Amazon QuickSight\n preserves the existing calculated column.

' + }, + ColumnName: { + type: 'string', + maxLength: 128, + minLength: 1, + description: '

Column name.

' + }, + Expression: { + type: 'string', + maxLength: 4096, + minLength: 1, + description: '

An expression that defines the calculated column.

' + } + }, + required: ['ColumnId', 'ColumnName', 'Expression'] + }, + CastColumnTypeOperation: { + type: 'object', + description: '

A transform operation that casts a column to a different type.

', + properties: { + ColumnName: { + type: 'string', + maxLength: 128, + minLength: 1, + description: '

Column name.

' + }, + Format: { + type: 'string', + maxLength: 32, + minLength: 0, + description: + '

When casting a column from string to datetime type, you can supply a string in a\n format supported by Amazon QuickSight to denote the source data format.

' + }, + NewColumnType: { + $ref: '#/definitions/ColumnDataType' + } + }, + required: ['ColumnName', 'NewColumnType'] + }, + ColumnDataType: { + type: 'string', + enum: ['STRING', 'INTEGER', 'DECIMAL', 'DATETIME'] + }, + ColumnDescription: { + type: 'object', + description: '

Metadata that contains a description for a column.

', + properties: { + Text: { + type: 'string', + maxLength: 500, + minLength: 0, + description: '

The text of a description for a column.

' + } + } + }, + ColumnGroup: { + type: 'object', + description: + '

Groupings of columns that work together in certain Amazon QuickSight features. This is\n a variant type structure. For this structure to be valid, only one of the attributes can\n be non-null.

', + properties: { + GeoSpatialColumnGroup: { + $ref: '#/definitions/GeoSpatialColumnGroup' + } + } + }, + ColumnLevelPermissionRule: { + type: 'object', + properties: { + ColumnNames: { + type: 'array', + items: { + type: 'string' + }, + minItems: 1 + }, + Principals: { + type: 'array', + items: { + type: 'string' + }, + maxItems: 100, + minItems: 1 + } + } + }, + ColumnTag: { + type: 'object', + description: + '

A tag for a column in a TagColumnOperation structure. This is a\n variant type structure. For this structure to be valid, only one of the attributes can\n be non-null.

', + properties: { + ColumnGeographicRole: { + $ref: '#/definitions/GeoSpatialDataRole' + }, + ColumnDescription: { + $ref: '#/definitions/ColumnDescription' + } + } + }, + CreateColumnsOperation: { + type: 'object', + description: + '

A transform operation that creates calculated columns. Columns created in one such\n operation form a lexical closure.

', + properties: { + Columns: { + type: 'array', + items: { + $ref: '#/definitions/CalculatedColumn' + }, + maxItems: 128, + minItems: 1, + description: '

Calculated columns to create.

' + } + }, + required: ['Columns'] + }, + CustomSql: { + type: 'object', + description: '

A physical table type built from the results of the custom SQL query.

', + properties: { + DataSourceArn: { + type: 'string', + description: '

The Amazon Resource Name (ARN) of the data source.

' + }, + SqlQuery: { + type: 'string', + maxLength: 65536, + minLength: 1, + description: '

The SQL query.

' + }, + Columns: { + type: 'array', + items: { + $ref: '#/definitions/InputColumn' + }, + maxItems: 2048, + minItems: 1, + description: '

The column schema from the SQL query result set.

' + }, + Name: { + type: 'string', + maxLength: 128, + minLength: 1, + description: '

A display name for the SQL query result.

' + } + }, + required: ['Columns', 'DataSourceArn', 'Name', 'SqlQuery'] + }, + DataSetImportMode: { + type: 'string', + enum: ['SPICE', 'DIRECT_QUERY'] + }, + FieldFolder: { + type: 'object', + properties: { + Description: { + type: 'string', + maxLength: 500, + minLength: 0 + }, + Columns: { + type: 'array', + items: { + type: 'string' + }, + maxItems: 5000, + minItems: 0 + } + } + }, + FieldFolderMap: { + type: 'object', + patternProperties: { + '.+': { + $ref: '#/definitions/FieldFolder' + } + } + }, + FileFormat: { + type: 'string', + enum: ['CSV', 'TSV', 'CLF', 'ELF', 'XLSX', 'JSON'] + }, + FilterOperation: { + type: 'object', + description: '

A transform operation that filters rows based on a condition.

', + properties: { + ConditionExpression: { + type: 'string', + maxLength: 4096, + minLength: 1, + description: + '

An expression that must evaluate to a Boolean value. Rows for which the expression\n evaluates to true are kept in the dataset.

' + } + }, + required: ['ConditionExpression'] + }, + GeoSpatialColumnGroup: { + type: 'object', + description: '

Geospatial column group that denotes a hierarchy.

', + properties: { + Columns: { + type: 'array', + items: { + type: 'string', + maxLength: 128, + minLength: 1 + }, + maxItems: 16, + minItems: 1, + description: '

Columns in this hierarchy.

' + }, + CountryCode: { + $ref: '#/definitions/GeoSpatialCountryCode' + }, + Name: { + type: 'string', + maxLength: 64, + minLength: 1, + description: '

A display name for the hierarchy.

' + } + }, + required: ['Columns', 'Name'] + }, + GeoSpatialCountryCode: { + type: 'string', + enum: ['US'] + }, + GeoSpatialDataRole: { + type: 'string', + enum: ['COUNTRY', 'STATE', 'COUNTY', 'CITY', 'POSTCODE', 'LONGITUDE', 'LATITUDE', 'POLITICAL1'] + }, + InputColumn: { + type: 'object', + description: '

Metadata for a column that is used as the input of a transform operation.

', + properties: { + Type: { + $ref: '#/definitions/InputColumnDataType' + }, + Name: { + type: 'string', + maxLength: 128, + minLength: 1, + description: '

The name of this column in the underlying data source.

' + } + }, + required: ['Name', 'Type'] + }, + InputColumnDataType: { + type: 'string', + enum: ['STRING', 'INTEGER', 'DECIMAL', 'DATETIME', 'BIT', 'BOOLEAN', 'JSON'] + }, + JoinInstruction: { + type: 'object', + description: '

Join instruction.

', + properties: { + OnClause: { + type: 'string', + maxLength: 512, + minLength: 1, + description: '

On Clause.

' + }, + Type: { + $ref: '#/definitions/JoinType' + }, + LeftJoinKeyProperties: { + $ref: '#/definitions/JoinKeyProperties' + }, + LeftOperand: { + type: 'string', + maxLength: 64, + minLength: 1, + pattern: '[0-9a-zA-Z-]*', + description: '

Left operand.

' + }, + RightOperand: { + type: 'string', + maxLength: 64, + minLength: 1, + pattern: '[0-9a-zA-Z-]*', + description: '

Right operand.

' + }, + RightJoinKeyProperties: { + $ref: '#/definitions/JoinKeyProperties' + } + }, + required: ['LeftOperand', 'OnClause', 'RightOperand', 'Type'] + }, + JoinKeyProperties: { + type: 'object', + properties: { + UniqueKey: { + type: 'boolean' + } + } + }, + JoinType: { + type: 'string', + enum: ['INNER', 'OUTER', 'LEFT', 'RIGHT'] + }, + LogicalTable: { + type: 'object', + description: + '

A logical table is a unit that joins and that data\n transformations operate on. A logical table has a source, which can be either a physical\n table or result of a join. When a logical table points to a physical table, the logical\n table acts as a mutable copy of that physical table through transform operations.

', + properties: { + Alias: { + type: 'string', + maxLength: 64, + minLength: 1, + description: '

A display name for the logical table.

' + }, + DataTransforms: { + type: 'array', + items: { + $ref: '#/definitions/TransformOperation' + }, + maxItems: 2048, + minItems: 1, + description: '

Transform operations that act on this logical table.

' + }, + Source: { + $ref: '#/definitions/LogicalTableSource' + } + }, + required: ['Alias', 'Source'] + }, + LogicalTableMap: { + type: 'object', + maxProperties: 64, + minProperties: 1, + patternProperties: { + '[0-9a-zA-Z-]*': { + $ref: '#/definitions/LogicalTable' + } + } + }, + LogicalTableSource: { + type: 'object', + description: + '

Information about the source of a logical table. This is a variant type structure. For\n this structure to be valid, only one of the attributes can be non-null.

', + properties: { + PhysicalTableId: { + type: 'string', + maxLength: 64, + minLength: 1, + pattern: '[0-9a-zA-Z-]*', + description: '

Physical table ID.

' + }, + JoinInstruction: { + $ref: '#/definitions/JoinInstruction' + } + } + }, + OutputColumn: { + type: 'object', + description: '

Output column.

', + properties: { + Type: { + $ref: '#/definitions/ColumnDataType' + }, + Description: { + type: 'string', + maxLength: 500, + minLength: 0, + description: '

A description for a column.

' + }, + Name: { + type: 'string', + maxLength: 128, + minLength: 1, + description: '

A display name for the dataset.

' + } + } + }, + PhysicalTable: { + type: 'object', + description: + '

A view of a data source that contains information about the shape of the data in the\n underlying source. This is a variant type structure. For this structure to be valid,\n only one of the attributes can be non-null.

', + properties: { + RelationalTable: { + $ref: '#/definitions/RelationalTable' + }, + CustomSql: { + $ref: '#/definitions/CustomSql' + }, + S3Source: { + $ref: '#/definitions/S3Source' + } + } + }, + PhysicalTableMap: { + type: 'object', + maxProperties: 32, + minProperties: 1, + patternProperties: { + '[0-9a-zA-Z-]*': { + $ref: '#/definitions/PhysicalTable' + } + } + }, + ProjectOperation: { + type: 'object', + description: + '

A transform operation that projects columns. Operations that come after a projection\n can only refer to projected columns.

', + properties: { + ProjectedColumns: { + type: 'array', + items: { + type: 'string' + }, + maxItems: 2000, + minItems: 1, + description: '

Projected columns.

' + } + }, + required: ['ProjectedColumns'] + }, + RelationalTable: { + type: 'object', + description: '

A physical table type for relational data sources.

', + properties: { + DataSourceArn: { + type: 'string', + description: '

The Amazon Resource Name (ARN) for the data source.

' + }, + InputColumns: { + type: 'array', + items: { + $ref: '#/definitions/InputColumn' + }, + maxItems: 2048, + minItems: 1, + description: '

The column schema of the table.

' + }, + Schema: { + type: 'string', + maxLength: 64, + minLength: 0, + description: '

The schema name. This name applies to certain relational database engines.

' + }, + Catalog: { + type: 'string', + description: '

The catalog associated with a table.

', + maxLength: 256, + minLength: 0 + }, + Name: { + type: 'string', + maxLength: 64, + minLength: 1, + description: '

The name of the relational table.

' + } + }, + required: ['DataSourceArn', 'InputColumns', 'Name'] + }, + RenameColumnOperation: { + type: 'object', + description: '

A transform operation that renames a column.

', + properties: { + NewColumnName: { + type: 'string', + maxLength: 128, + minLength: 1, + description: '

The new name for the column.

' + }, + ColumnName: { + type: 'string', + maxLength: 128, + minLength: 1, + description: '

The name of the column to be renamed.

' + } + }, + required: ['ColumnName', 'NewColumnName'] + }, + ResourcePermission: { + type: 'object', + description: '

Permission for the resource.

', + properties: { + Actions: { + type: 'array', + items: { + type: 'string' + }, + maxItems: 16, + minItems: 1, + description: '

The IAM action to grant or revoke permissions on.

' + }, + Principal: { + type: 'string', + maxLength: 256, + minLength: 1, + description: + '

The Amazon Resource Name (ARN) of the principal. This can be one of the\n following:

\n
    \n
  • \n

    The ARN of an Amazon QuickSight user or group associated with a data source or dataset. (This is common.)

    \n
  • \n
  • \n

    The ARN of an Amazon QuickSight user, group, or namespace associated with an analysis, dashboard, template, or theme. (This is common.)

    \n
  • \n
  • \n

    The ARN of an AWS account root: This is an IAM ARN rather than a QuickSight\n ARN. Use this option only to share resources (templates) across AWS accounts.\n (This is less common.)

    \n
  • \n
' + } + }, + required: ['Actions', 'Principal'] + }, + RowLevelPermissionDataSet: { + type: 'object', + description: '

The row-level security configuration for the dataset.

', + properties: { + Arn: { + type: 'string', + description: '

The Amazon Resource Name (ARN) of the permission dataset.

' + }, + Namespace: { + type: 'string', + maxLength: 64, + minLength: 0, + pattern: '^[a-zA-Z0-9._-]*$', + description: '

The namespace associated with the row-level permissions dataset.

' + }, + PermissionPolicy: { + $ref: '#/definitions/RowLevelPermissionPolicy' + }, + FormatVersion: { + $ref: '#/definitions/RowLevelPermissionFormatVersion' + } + }, + required: ['Arn', 'PermissionPolicy'] + }, + RowLevelPermissionPolicy: { + type: 'string', + enum: ['GRANT_ACCESS', 'DENY_ACCESS'] + }, + RowLevelPermissionFormatVersion: { + type: 'string', + enum: ['VERSION_1', 'VERSION_2'] + }, + S3Source: { + type: 'object', + description: '

A physical table type for as S3 data source.

', + properties: { + DataSourceArn: { + type: 'string', + description: '

The amazon Resource Name (ARN) for the data source.

' + }, + InputColumns: { + type: 'array', + items: { + $ref: '#/definitions/InputColumn' + }, + maxItems: 2048, + minItems: 1, + description: '

A physical table type for as S3 data source.

' + }, + UploadSettings: { + $ref: '#/definitions/UploadSettings' + } + }, + required: ['DataSourceArn', 'InputColumns'] + }, + Tag: { + type: 'object', + description: + '

The key or keys of the key-value pairs for the resource tag or tags assigned to the\n resource.

', + properties: { + Value: { + type: 'string', + maxLength: 256, + minLength: 1, + description: '

Tag value.

' + }, + Key: { + type: 'string', + maxLength: 128, + minLength: 1, + description: '

Tag key.

' + } + }, + required: ['Key', 'Value'] + }, + TagColumnOperation: { + type: 'object', + description: '

A transform operation that tags a column with additional information.

', + properties: { + ColumnName: { + type: 'string', + maxLength: 128, + minLength: 1, + description: '

The column that this operation acts on.

' + }, + Tags: { + type: 'array', + items: { + $ref: '#/definitions/ColumnTag' + }, + maxItems: 16, + minItems: 1, + description: + '

The dataset column tag, currently only used for geospatial type tagging. .

\n \n

This is not tags for the AWS tagging feature. .

\n
' + } + }, + required: ['ColumnName', 'Tags'] + }, + TextQualifier: { + type: 'string', + enum: ['DOUBLE_QUOTE', 'SINGLE_QUOTE'] + }, + TransformOperation: { + type: 'object', + description: + '

A data transformation on a logical table. This is a variant type structure. For this\n structure to be valid, only one of the attributes can be non-null.

', + properties: { + TagColumnOperation: { + $ref: '#/definitions/TagColumnOperation' + }, + FilterOperation: { + $ref: '#/definitions/FilterOperation' + }, + CastColumnTypeOperation: { + $ref: '#/definitions/CastColumnTypeOperation' + }, + CreateColumnsOperation: { + $ref: '#/definitions/CreateColumnsOperation' + }, + RenameColumnOperation: { + $ref: '#/definitions/RenameColumnOperation' + }, + ProjectOperation: { + $ref: '#/definitions/ProjectOperation' + } + } + }, + UploadSettings: { + type: 'object', + description: '

Information about the format for a source file or files.

', + properties: { + ContainsHeader: { + type: 'boolean', + description: '

Whether the file has a header row, or the files each have a header row.

' + }, + TextQualifier: { + $ref: '#/definitions/TextQualifier' + }, + Format: { + $ref: '#/definitions/FileFormat' + }, + StartFromRow: { + type: 'number', + minimum: 1, + description: '

A row number to start reading data from.

' + }, + Delimiter: { + type: 'string', + maxLength: 1, + minLength: 1, + description: '

The delimiter between values in the file.

' + } + } + }, + IngestionWaitPolicy: { + type: 'object', + description: + '

Wait policy to use when creating/updating dataset. Default is to wait for SPICE ingestion to finish with timeout of 36 hours.

', + properties: { + WaitForSpiceIngestion: { + type: 'boolean', + description: + '

Wait for SPICE ingestion to finish to mark dataset creation/update successful. Default (true).\n Applicable only when DataSetImportMode mode is set to SPICE.

', + default: true + }, + IngestionWaitTimeInHours: { + type: 'number', + description: + '

The maximum time (in hours) to wait for Ingestion to complete. Default timeout is 36 hours.\n Applicable only when DataSetImportMode mode is set to SPICE and WaitForSpiceIngestion is set to true.

', + minimum: 1, + maximum: 36, + default: 36 + } + } + } + }, + properties: { + Arn: { + type: 'string', + description: '

The Amazon Resource Name (ARN) of the resource.

' + }, + AwsAccountId: { + type: 'string', + maxLength: 12, + minLength: 12, + pattern: '^[0-9]{12}$' + }, + ColumnGroups: { + type: 'array', + items: { + $ref: '#/definitions/ColumnGroup' + }, + maxItems: 8, + minItems: 1, + description: + '

Groupings of columns that work together in certain QuickSight features. Currently, only geospatial hierarchy is supported.

' + }, + ColumnLevelPermissionRules: { + type: 'array', + items: { + $ref: '#/definitions/ColumnLevelPermissionRule' + }, + minItems: 1 + }, + ConsumedSpiceCapacityInBytes: { + type: 'number', + description: + "

The amount of SPICE capacity used by this dataset. This is 0 if the dataset isn't\n imported into SPICE.

" + }, + CreatedTime: { + type: 'string', + description: '

The time that this dataset was created.

', + format: 'string' + }, + DataSetId: { + type: 'string' + }, + FieldFolders: { + $ref: '#/definitions/FieldFolderMap' + }, + ImportMode: { + $ref: '#/definitions/DataSetImportMode' + }, + LastUpdatedTime: { + type: 'string', + description: '

The last time that this dataset was updated.

', + format: 'string' + }, + LogicalTableMap: { + $ref: '#/definitions/LogicalTableMap' + }, + Name: { + type: 'string', + maxLength: 128, + minLength: 1, + description: '

The display name for the dataset.

' + }, + OutputColumns: { + type: 'array', + items: { + $ref: '#/definitions/OutputColumn' + }, + description: + '

The list of columns after all transforms. These columns are available in templates,\n analyses, and dashboards.

' + }, + Permissions: { + type: 'array', + items: { + $ref: '#/definitions/ResourcePermission' + }, + maxItems: 64, + minItems: 1, + description: '

A list of resource permissions on the dataset.

' + }, + PhysicalTableMap: { + $ref: '#/definitions/PhysicalTableMap' + }, + RowLevelPermissionDataSet: { + $ref: '#/definitions/RowLevelPermissionDataSet' + }, + Tags: { + type: 'array', + items: { + $ref: '#/definitions/Tag' + }, + maxItems: 200, + minItems: 1, + description: '

Contains a map of the key-value pairs for the resource tag or tags assigned to the dataset.

' + }, + IngestionWaitPolicy: { + $ref: '#/definitions/IngestionWaitPolicy' + } + }, + readOnlyProperties: [ + '/properties/Arn', + '/properties/ConsumedSpiceCapacityInBytes', + '/properties/CreatedTime', + '/properties/LastUpdatedTime', + '/properties/OutputColumns' + ], + writeOnlyProperties: ['/properties/FieldFolders', '/properties/IngestionWaitPolicy'], + createOnlyProperties: ['/properties/AwsAccountId', '/properties/DataSetId'], + primaryIdentifier: ['/properties/AwsAccountId', '/properties/DataSetId'], + additionalProperties: false, + handlers: { + create: { + permissions: [ + 'quicksight:DescribeDataSet', + 'quicksight:DescribeDataSetPermissions', + 'quicksight:DescribeIngestion', + 'quicksight:CreateDataSet', + 'quicksight:PassDataSource', + 'quicksight:PassDataSet', + 'quicksight:TagResource', + 'quicksight:ListTagsForResource' + ] + }, + read: { + permissions: [ + 'quicksight:DescribeDataSet', + 'quicksight:DescribeDataSetPermissions', + 'quicksight:ListTagsForResource' + ] + }, + update: { + permissions: [ + 'quicksight:DescribeDataSet', + 'quicksight:DescribeDataSetPermissions', + 'quicksight:PassDataSource', + 'quicksight:UpdateDataSet', + 'quicksight:UpdateDataSetPermissions', + 'quicksight:PassDataSet', + 'quicksight:DescribeIngestion', + 'quicksight:ListIngestions', + 'quicksight:CancelIngestion', + 'quicksight:TagResource', + 'quicksight:UntagResource', + 'quicksight:ListTagsForResource' + ] + }, + delete: { + permissions: [ + 'quicksight:DescribeDataSet', + 'quicksight:DeleteDataSet', + 'quicksight:ListTagsForResource', + 'quicksight:DescribeIngestion' + ] + }, + list: { + permissions: ['quicksight:DescribeDataSet', 'quicksight:ListDataSets'] + } + } +} diff --git a/test/normalizer/removeMaxItems.1.json b/test/normalizer/removeMaxItems.1.json new file mode 100644 index 00000000..b01fe130 --- /dev/null +++ b/test/normalizer/removeMaxItems.1.json @@ -0,0 +1,66 @@ +{ + "name": "Remove maxItems if it is big enough to likely cause OOMs (1)", + "in": { + "additionalProperties": false, + "id": "RemoveMaxItems", + "properties": { + "a": { + "minItems": 5, + "type": "array" + }, + "b": { + "maxItems": 50, + "minItems": 5, + "type": "array" + }, + "c": { + "maxItems": 50, + "type": "array" + }, + "d": { + "maxItems": 15, + "minItems": 5, + "type": "array" + }, + "e": { + "maxItems": 15, + "type": "array" + } + }, + "required": [] + }, + "out": { + "additionalProperties": false, + "id": "RemoveMaxItems", + "properties": { + "a": { + "description": "@minItems 5", + "minItems": 5, + "type": "array" + }, + "b": { + "description": "@minItems 5\n@maxItems 50", + "minItems": 5, + "type": "array" + }, + "c": { + "description": "@maxItems 50", + "minItems": 0, + "type": "array" + }, + "d": { + "description": "@minItems 5\n@maxItems 15", + "maxItems": 15, + "minItems": 5, + "type": "array" + }, + "e": { + "description": "@maxItems 15", + "maxItems": 15, + "minItems": 0, + "type": "array" + } + }, + "required": [] + } +} diff --git a/test/normalizer/removeMaxItems.2.json b/test/normalizer/removeMaxItems.2.json new file mode 100644 index 00000000..fe6d93da --- /dev/null +++ b/test/normalizer/removeMaxItems.2.json @@ -0,0 +1,71 @@ +{ + "name": "Remove maxItems if it is big enough to likely cause OOMs (2)", + "in": { + "additionalProperties": false, + "id": "RemoveMaxItems", + "properties": { + "a": { + "minItems": 5, + "type": "array" + }, + "b": { + "maxItems": 50, + "minItems": 5, + "type": "array" + }, + "c": { + "maxItems": 500, + "type": "array" + }, + "d": { + "maxItems": 15, + "minItems": 5, + "type": "array" + }, + "e": { + "maxItems": 15, + "type": "array" + } + }, + "required": [] + }, + "out": { + "additionalProperties": false, + "id": "RemoveMaxItems", + "properties": { + "a": { + "description": "@minItems 5", + "minItems": 5, + "type": "array" + }, + "b": { + "description": "@minItems 5\n@maxItems 50", + "maxItems": 50, + "minItems": 5, + "type": "array" + }, + "c": { + "description": "@maxItems 500", + "maxItems": 500, + "minItems": 0, + "type": "array" + }, + "d": { + "description": "@minItems 5\n@maxItems 15", + "maxItems": 15, + "minItems": 5, + "type": "array" + }, + "e": { + "description": "@maxItems 15", + "maxItems": 15, + "minItems": 0, + "type": "array" + } + }, + "required": [] + }, + "options": { + "maxItems": 1000 + } +} diff --git a/test/normalizer/removeMaxItems.3.json b/test/normalizer/removeMaxItems.3.json new file mode 100644 index 00000000..6f137477 --- /dev/null +++ b/test/normalizer/removeMaxItems.3.json @@ -0,0 +1,69 @@ +{ + "name": "Remove maxItems if it is big enough to likely cause OOMs (3)", + "in": { + "additionalProperties": false, + "id": "RemoveMaxItems", + "properties": { + "a": { + "description": "Test", + "minItems": 5, + "type": "array" + }, + "b": { + "description": "Test", + "maxItems": 50, + "minItems": 5, + "type": "array" + }, + "c": { + "maxItems": 50, + "type": "array" + }, + "d": { + "maxItems": 15, + "minItems": 5, + "type": "array" + }, + "e": { + "maxItems": 15, + "type": "array" + } + }, + "required": [] + }, + "out": { + "additionalProperties": false, + "id": "RemoveMaxItems", + "properties": { + "a": { + "description": "Test\n\n@minItems 5", + "minItems": 5, + "type": "array" + }, + "b": { + "description": "Test\n\n@minItems 5\n@maxItems 50", + "minItems": 5, + "type": "array" + }, + "c": { + "description": "@maxItems 50", + "minItems": 0, + "type": "array" + }, + "d": { + "description": "@minItems 5\n@maxItems 15", + "minItems": 5, + "type": "array" + }, + "e": { + "description": "@maxItems 15", + "minItems": 0, + "type": "array" + } + }, + "required": [] + }, + "options": { + "maxItems": -1 + } +} diff --git a/test/normalizer/schemaIgnoreMaxMinItems.json b/test/normalizer/schemaIgnoreMaxMinItems.json index 3168a4d2..3cfe53c4 100644 --- a/test/normalizer/schemaIgnoreMaxMinItems.json +++ b/test/normalizer/schemaIgnoreMaxMinItems.json @@ -34,18 +34,30 @@ "type": "object", "properties": { "unbounded": { - "type": ["array", "string"] + "type": [ + "array", + "string" + ] }, "minOnly": { - "type": ["array", "string"], + "type": [ + "array", + "string" + ], "minItems": 1 }, "maxOnly": { - "type": ["array", "string"], + "type": [ + "array", + "string" + ], "maxItems": 2 }, "minAndMax": { - "type": ["array", "string"], + "type": [ + "array", + "string" + ], "minItems": 1, "maxItems": 2 } @@ -160,12 +172,15 @@ "type": "array" }, "minOnly": { + "description": "@minItems 1", "type": "array" }, "maxOnly": { + "description": "@maxItems 2", "type": "array" }, "minAndMax": { + "description": "@minItems 1\n@maxItems 2", "type": "array" } }, @@ -176,16 +191,31 @@ "type": "object", "properties": { "unbounded": { - "type": ["array", "string"] + "type": [ + "array", + "string" + ] }, "minOnly": { - "type": ["array", "string"] + "description": "@minItems 1", + "type": [ + "array", + "string" + ] }, "maxOnly": { - "type": ["array", "string"] + "description": "@maxItems 2", + "type": [ + "array", + "string" + ] }, "minAndMax": { - "type": ["array", "string"] + "description": "@minItems 1\n@maxItems 2", + "type": [ + "array", + "string" + ] } }, "additionalProperties": false, @@ -200,6 +230,7 @@ } }, "minOnly": { + "description": "@minItems 1", "items": { "type": "string" }, @@ -208,11 +239,13 @@ } }, "maxOnly": { + "description": "@maxItems 2", "items": { "type": "string" } }, "minAndMax": { + "description": "@minItems 1\n@maxItems 2", "items": { "type": "string" } @@ -238,6 +271,7 @@ "minOnly": { "anyOf": [ { + "description": "@minItems 1", "items": { "type": "string" }, @@ -252,6 +286,7 @@ "maxOnly": { "anyOf": [ { + "description": "@maxItems 2", "items": { "type": "string" } @@ -263,6 +298,7 @@ "minAndMax": { "anyOf": [ { + "description": "@minItems 1\n@maxItems 2", "items": { "type": "string" } diff --git a/test/normalizer/schemaItems.json b/test/normalizer/schemaItems.json index 3030c10c..c4ec54ad 100644 --- a/test/normalizer/schemaItems.json +++ b/test/normalizer/schemaItems.json @@ -93,6 +93,7 @@ "minItems": 0 }, "typedMinBounded": { + "description": "@minItems 2", "items": [ { "type": "string" @@ -107,6 +108,7 @@ "minItems": 2 }, "typedMaxBounded": { + "description": "@maxItems 2", "items": [ { "type": "string" @@ -119,6 +121,7 @@ "minItems": 0 }, "typedMinMaxBounded": { + "description": "@minItems 2\n@maxItems 5", "items": [ { "type": "string" @@ -140,6 +143,7 @@ "maxItems": 5 }, "moreItemsThanMax": { + "description": "@maxItems 1", "items": [ { "type": "string" @@ -149,6 +153,7 @@ "minItems": 0 }, "itemAnyOf": { + "description": "@maxItems 1", "items": [ { "anyOf": [ @@ -169,6 +174,7 @@ "baseAnyOf": { "anyOf": [ { + "description": "@maxItems 1", "items": [ { "type": "string" @@ -178,6 +184,7 @@ "minItems": 0 }, { + "description": "@maxItems 2", "items": [ { "type": "number" diff --git a/test/normalizer/schemaMinItems.json b/test/normalizer/schemaMinItems.json index af1f2193..c64cb8c8 100644 --- a/test/normalizer/schemaMinItems.json +++ b/test/normalizer/schemaMinItems.json @@ -31,18 +31,30 @@ "type": "object", "properties": { "unbounded": { - "type": ["array", "string"] + "type": [ + "array", + "string" + ] }, "minOnly": { - "type": ["array", "string"], + "type": [ + "array", + "string" + ], "minItems": 1 }, "maxOnly": { - "type": ["array", "string"], + "type": [ + "array", + "string" + ], "maxItems": 2 }, "minAndMax": { - "type": ["array", "string"], + "type": [ + "array", + "string" + ], "minItems": 1, "maxItems": 2 } @@ -158,15 +170,18 @@ "minItems": 0 }, "minOnly": { + "description": "@minItems 1", "type": "array", "minItems": 1 }, "maxOnly": { + "description": "@maxItems 2", "type": "array", "maxItems": 2, "minItems": 0 }, "minAndMax": { + "description": "@minItems 1\n@maxItems 2", "type": "array", "minItems": 1, "maxItems": 2 @@ -179,20 +194,35 @@ "type": "object", "properties": { "unbounded": { - "type": ["array", "string"], + "type": [ + "array", + "string" + ], "minItems": 0 }, "minOnly": { - "type": ["array", "string"], + "description": "@minItems 1", + "type": [ + "array", + "string" + ], "minItems": 1 }, "maxOnly": { - "type": ["array", "string"], + "description": "@maxItems 2", + "type": [ + "array", + "string" + ], "maxItems": 2, "minItems": 0 }, "minAndMax": { - "type": ["array", "string"], + "description": "@minItems 1\n@maxItems 2", + "type": [ + "array", + "string" + ], "minItems": 1, "maxItems": 2 } @@ -210,6 +240,7 @@ "minItems": 0 }, "minOnly": { + "description": "@minItems 1", "additionalItems": { "type": "string" }, @@ -221,6 +252,7 @@ "minItems": 1 }, "maxOnly": { + "description": "@maxItems 2", "items": [ { "type": "string" @@ -233,6 +265,7 @@ "minItems": 0 }, "minAndMax": { + "description": "@minItems 1\n@maxItems 2", "items": [ { "type": "string" @@ -266,6 +299,7 @@ "minOnly": { "anyOf": [ { + "description": "@minItems 1", "items": [ { "type": "string" @@ -283,6 +317,7 @@ "maxOnly": { "anyOf": [ { + "description": "@maxItems 2", "items": [ { "type": "string" @@ -301,6 +336,7 @@ "minAndMax": { "anyOf": [ { + "description": "@minItems 1\n@maxItems 2", "items": [ { "type": "string" diff --git a/test/testNormalizer.ts b/test/testNormalizer.ts index 41cf318d..ae37a63d 100644 --- a/test/testNormalizer.ts +++ b/test/testNormalizer.ts @@ -1,6 +1,5 @@ import test from 'ava' import {readdirSync} from 'fs' -import {template} from 'lodash' import {join} from 'path' import {JSONSchema, Options, DEFAULT_OPTIONS} from '../src' import {link} from '../src/linker' @@ -21,15 +20,9 @@ export function run() { .map(_ => join(normalizerDir, _)) .map(_ => [_, require(_)] as [string, JSONTestCase]) .forEach(([filename, json]: [string, JSONTestCase]) => { - const params = {filename} test(json.name, t => { - const normalized = normalize(link(json.in), filename, json.options || DEFAULT_OPTIONS) - t.snapshot(template(toString(normalized))(params)) + const normalized = normalize(link(json.in), filename, json.options ?? DEFAULT_OPTIONS) t.deepEqual(json.out, normalized) }) }) } - -function toString(json: Record): string { - return JSON.stringify(json, null, 2) -}