diff --git a/README.md b/README.md index d9e50cdb..c5ad4043 100644 --- a/README.md +++ b/README.md @@ -139,6 +139,7 @@ See [server demo](example) and [browser demo](https://github.com/bcherny/json-sc | declareExternallyReferenced | boolean | `true` | Declare external schemas referenced via `$ref`? | | enableConstEnums | boolean | `true` | Prepend enums with [`const`](https://www.typescriptlang.org/docs/handbook/enums.html#computed-and-constant-members)? | | inferStringEnumKeysFromValues | boolean | `false` | Create enums from JSON enums with eponymous keys | +| readonly | boolean | false | Generate all properties and array types as readonly. When true, all properties in interfaces will be prefixed with 'readonly', array types will be generated as 'readonly T[]', and index signatures will be readonly. | 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`. diff --git a/src/generator.ts b/src/generator.ts index fb8d23b0..6e1aa716 100644 --- a/src/generator.ts +++ b/src/generator.ts @@ -157,6 +157,10 @@ function generateTypeUnmemoized(ast: AST, options: Options): string { return `${type} | undefined` } + if (options.readonly && ast.type === 'ARRAY') { + return `readonly ${type}` + } + return type } export const generateType = memoize(generateTypeUnmemoized) @@ -305,6 +309,7 @@ function generateInterface(ast: TInterface, options: Options): string { .map( ([isRequired, keyName, ast, type]) => (hasComment(ast) && !ast.standaloneName ? generateComment(ast.comment, ast.deprecated) + '\n' : '') + + (options.readonly ? 'readonly ' : '') + escapeKeyName(keyName) + (isRequired ? '' : '?') + ': ' + diff --git a/src/index.ts b/src/index.ts index 1aa67be0..ec318b3b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -52,6 +52,12 @@ export interface Options { * Create enums from JSON enums with eponymous keys */ inferStringEnumKeysFromValues: boolean + /** + * Generate all properties and array types as readonly. + * When true, all properties in interfaces will be prefixed with 'readonly', + * array types will be generated as 'readonly T[]', and index signatures will be readonly. + */ + readonly: boolean /** * Format code? Set this to `false` to improve performance. */ @@ -100,6 +106,7 @@ export const DEFAULT_OPTIONS: Options = { declareExternallyReferenced: true, enableConstEnums: true, inferStringEnumKeysFromValues: false, + readonly: false, format: true, ignoreMinAndMaxItems: false, maxItems: 20, diff --git a/test/__snapshots__/test/test.ts.md b/test/__snapshots__/test/test.ts.md index da07fbea..fd9125ef 100644 --- a/test/__snapshots__/test/test.ts.md +++ b/test/__snapshots__/test/test.ts.md @@ -4,6 +4,28 @@ The actual snapshot is saved in `test.ts.snap`. Generated by [AVA](https://avajs.dev). +## readonly.js + +> Expected output to match snapshot for e2e test: readonly.js + + `/* eslint-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 interface Readonly {␊ + readonly user?: {␊ + readonly name?: string;␊ + readonly age?: number;␊ + readonly hobbies?: readonly string[];␊ + readonly [k: string]: unknown;␊ + };␊ + readonly [k: string]: unknown;␊ + }␊ + ` + ## JSONSchema.js > Expected output to match snapshot for e2e test: JSONSchema.js diff --git a/test/__snapshots__/test/test.ts.snap b/test/__snapshots__/test/test.ts.snap index 564bd36c..24aa30e8 100644 Binary files a/test/__snapshots__/test/test.ts.snap and b/test/__snapshots__/test/test.ts.snap differ diff --git a/test/e2e/readonly.ts b/test/e2e/readonly.ts new file mode 100644 index 00000000..0a3c98ef --- /dev/null +++ b/test/e2e/readonly.ts @@ -0,0 +1,31 @@ +export const input = { + $schema: 'http://json-schema.org/draft-07/schema', + type: 'object', + properties: { + user: { + type: 'object', + properties: { + name: {type: 'string'}, + age: {type: 'number'}, + hobbies: { + type: 'array', + items: {type: 'string'}, + }, + }, + }, + }, +} + +export const options = { + readonly: true, +} + +export const output = `export interface User { + readonly name?: string; + readonly age?: number; + readonly hobbies?: readonly string[]; +} + +export interface Root { + readonly user?: User; +}`