Skip to content

Commit 01922e3

Browse files
authored
feat: add readonly flag (#82)
1 parent c8fffc9 commit 01922e3

28 files changed

+322
-184
lines changed

CONTRIBUTING.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,21 @@
11
# Contributing
2+
3+
## Build
4+
5+
```bash
6+
pnpm run build
7+
```
8+
9+
## Test
10+
11+
Snapshot Update
12+
13+
```bash
14+
pnpm run update:snapshot
15+
```
16+
17+
## Shortcut
18+
19+
```bash
20+
pnpm run build && pnpm run test:code:gen && pnpm run update:snapshot
21+
```

src/code-templates/_shared/ApiClientArgument.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ const createHeaders = (factory: TsGenerator.Factory.Type, { convertedParams }: C
5757
if (convertedParams.has2OrMoreRequestContentTypes) {
5858
members.push(
5959
factory.PropertySignature.create({
60+
readOnly: false,
6061
name: `"Content-Type"`,
6162
optional: false,
6263
type: factory.TypeReferenceNode.create({ name: "T" }),
@@ -67,6 +68,7 @@ const createHeaders = (factory: TsGenerator.Factory.Type, { convertedParams }: C
6768
if (convertedParams.has2OrMoreSuccessResponseContentTypes) {
6869
members.push(
6970
factory.PropertySignature.create({
71+
readOnly: false,
7072
name: `Accept`,
7173
optional: false,
7274
type: factory.TypeReferenceNode.create({ name: "U" }),
@@ -117,6 +119,7 @@ export const create = (factory: TsGenerator.Factory.Type, params: CodeGenerator.
117119
const headerDeclaration = createHeaders(factory, params);
118120
if (headerDeclaration) {
119121
const extraHeader = factory.PropertySignature.create({
122+
readOnly: false,
120123
name: "headers",
121124
optional: false,
122125
type: headerDeclaration,
@@ -126,6 +129,7 @@ export const create = (factory: TsGenerator.Factory.Type, params: CodeGenerator.
126129

127130
if (convertedParams.hasParameter) {
128131
const parameter = factory.PropertySignature.create({
132+
readOnly: false,
129133
name: "parameter",
130134
optional: false,
131135
type: factory.TypeReferenceNode.create({
@@ -137,6 +141,7 @@ export const create = (factory: TsGenerator.Factory.Type, params: CodeGenerator.
137141

138142
if (convertedParams.hasRequestBody) {
139143
const requestBody = factory.PropertySignature.create({
144+
readOnly: false,
140145
name: "requestBody",
141146
optional: false,
142147
type: factory.IndexedAccessTypeNode.create({

src/code-templates/_shared/ApiClientInterface.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,16 +63,19 @@ const createQueryParamsDeclarations = (factory: TsGenerator.Factory.Type) => {
6363
name: "QueryParameter",
6464
members: [
6565
factory.PropertySignature.create({
66+
readOnly: false,
6667
name: "value",
6768
optional: false,
6869
type: factory.TypeNode.create({ type: "any" }),
6970
}),
7071
factory.PropertySignature.create({
72+
readOnly: false,
7173
name: "style",
7274
optional: true,
7375
type: factory.TypeNode.create({ type: "string", enum: ["form", "spaceDelimited", "pipeDelimited", "deepObject"] }),
7476
}),
7577
factory.PropertySignature.create({
78+
readOnly: false,
7679
name: "explode",
7780
optional: false,
7881
type: factory.TypeNode.create({ type: "boolean" }),
@@ -113,32 +116,37 @@ const createEncodingInterface = (factory: TsGenerator.Factory.Type) => {
113116
members: [
114117
factory.PropertySignature.create({
115118
name: "contentType",
119+
readOnly: true,
116120
optional: true,
117121
type: factory.TypeReferenceNode.create({
118122
name: "string",
119123
}),
120124
}),
121125
factory.PropertySignature.create({
122126
name: "headers",
127+
readOnly: false,
123128
optional: true,
124129
type: factory.TypeReferenceNode.create({
125130
name: "Record<string, any>",
126131
}),
127132
}),
128133
factory.PropertySignature.create({
129134
name: "style",
135+
readOnly: true,
130136
optional: true,
131137
type: factory.TypeNode.create({ type: "string", enum: ["form", "spaceDelimited", "pipeDelimited", "deepObject"] }),
132138
}),
133139
factory.PropertySignature.create({
134140
name: "explode",
141+
readOnly: true,
135142
optional: true,
136143
type: factory.TypeReferenceNode.create({
137144
name: "boolean",
138145
}),
139146
}),
140147
factory.PropertySignature.create({
141148
name: "allowReserved",
149+
readOnly: true,
142150
optional: true,
143151
type: factory.TypeReferenceNode.create({
144152
name: "boolean",
@@ -219,6 +227,7 @@ export const create = (
219227
});
220228

221229
const requestFunction = factory.PropertySignature.create({
230+
readOnly: false,
222231
name: "request",
223232
optional: false,
224233
type: functionType,
@@ -230,32 +239,38 @@ export const create = (
230239
members: [
231240
factory.PropertySignature.create({
232241
name: `httpMethod`,
242+
readOnly: true,
233243
optional: false,
234244
type: factory.TypeReferenceNode.create({ name: "HttpMethod" }),
235245
}),
236246
factory.PropertySignature.create({
237247
name: methodType === "currying-function" ? "uri" : "url",
248+
readOnly: true,
238249
optional: false,
239250
type: factory.TypeReferenceNode.create({ name: "string" }),
240251
}),
241252
factory.PropertySignature.create({
242253
name: `headers`,
254+
readOnly: false,
243255
optional: false,
244256
type: objectLikeOrAnyType,
245257
}),
246258
factory.PropertySignature.create({
247259
name: `requestBody`,
260+
readOnly: false,
248261
optional: true,
249262
type: objectLikeOrAnyType,
250263
}),
251264
factory.PropertySignature.create({
252265
name: `requestBodyEncoding`,
266+
readOnly: false,
253267
optional: true,
254268
type: factory.TypeReferenceNode.create({ name: "Record<string, Encoding>" }),
255269
}),
256270
factory.PropertySignature.create({
257271
name: `queryParameters`,
258272
optional: true,
273+
readOnly: false,
259274
type: factory.UnionTypeNode.create({
260275
typeNodes: [
261276
factory.TypeReferenceNode.create({

src/internal/OpenApiTools/components/Header.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export const generatePropertySignature = (
3737
if (reference.type === "local") {
3838
context.setReferenceHandler(currentPoint, reference);
3939
return factory.PropertySignature.create({
40+
readOnly: false,
4041
name: converterContext.escapePropertySignatureName(name),
4142
optional: false,
4243
type: factory.TypeReferenceNode.create({
@@ -45,6 +46,7 @@ export const generatePropertySignature = (
4546
});
4647
}
4748
return factory.PropertySignature.create({
49+
readOnly: false,
4850
name: converterContext.escapePropertySignatureName(name),
4951
optional: false,
5052
type: factory.TypeReferenceNode.create({
@@ -53,6 +55,7 @@ export const generatePropertySignature = (
5355
});
5456
}
5557
return factory.PropertySignature.create({
58+
readOnly: false,
5659
name: converterContext.escapePropertySignatureName(name),
5760
optional: false,
5861
type: ToTypeNode.convert(entryPoint, currentPoint, factory, header.schema || { type: "null" }, context, converterContext),

src/internal/OpenApiTools/components/MediaType.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export const generatePropertySignature = (
1515
converterContext: ConverterContext.Types,
1616
): ts.PropertySignature => {
1717
return factory.PropertySignature.create({
18+
readOnly: false,
1819
name: converterContext.escapePropertySignatureName(protocol),
1920
optional: false,
2021
type: ToTypeNode.convert(entryPoint, currentPoint, factory, schema, context, converterContext),

src/internal/OpenApiTools/components/Parameter.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ export const generatePropertySignatureObject = (
5353
const isPathProperty = localRef.in === "path";
5454
const name = converterContext.escapePropertySignatureName(localRef.name);
5555
const typeElement = factory.PropertySignature.create({
56+
readOnly: false,
5657
name: name,
5758
optional: isPathProperty ? false : !localRef.required,
5859
comment: localRef.description,
@@ -68,6 +69,7 @@ export const generatePropertySignatureObject = (
6869
const isPathProperty = reference.data.in === "path";
6970
const name = converterContext.escapePropertySignatureName(reference.data.name);
7071
const typeElement = factory.PropertySignature.create({
72+
readOnly: false,
7173
name: name,
7274
optional: isPathProperty ? false : !reference.data.required,
7375
comment: reference.data.description,
@@ -88,6 +90,7 @@ export const generatePropertySignatureObject = (
8890
const isPathProperty = parameter.in === "path";
8991
const name = converterContext.escapePropertySignatureName(parameter.name);
9092
const typeElement = factory.PropertySignature.create({
93+
readOnly: false,
9194
name: name,
9295
optional: isPathProperty ? false : !parameter.required,
9396
type: ToTypeNode.convert(entryPoint, currentPoint, factory, parameter.schema || { type: "null" }, context, converterContext),

src/internal/OpenApiTools/components/Schema.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ export const generatePropertySignatures = (
3939
return Object.entries(schema.properties).map(([propertyName, property]) => {
4040
if (!property) {
4141
return factory.PropertySignature.create({
42+
readOnly: false,
4243
name: convertContext.escapePropertySignatureName(propertyName),
4344
optional: !required.includes(propertyName),
4445
comment: [schema.title, schema.description].filter(v => !!v).join("\n\n"),
@@ -48,6 +49,7 @@ export const generatePropertySignatures = (
4849
});
4950
}
5051
return factory.PropertySignature.create({
52+
readOnly: typeof property !== "boolean" ? !!property.readOnly : false,
5153
name: convertContext.escapePropertySignatureName(propertyName),
5254
optional: !required.includes(propertyName),
5355
type: ToTypeNode.convert(entryPoint, currentPoint, factory, property, context, convertContext, { parent: schema }),

src/internal/OpenApiTools/components/SecuritySchema.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,25 @@ export const generatePropertySignatures = (
1111
): ts.PropertySignature[] => {
1212
const signatures: ts.PropertySignature[] = [
1313
factory.PropertySignature.create({
14+
readOnly: false,
1415
name: "type",
1516
optional: false,
1617
type: factory.LiteralTypeNode.create({ value: securitySchema.type }),
1718
}),
1819
factory.PropertySignature.create({
20+
readOnly: false,
1921
name: "name",
2022
optional: false,
2123
type: factory.LiteralTypeNode.create({ value: securitySchema.name }),
2224
}),
2325
factory.PropertySignature.create({
26+
readOnly: false,
2427
name: "in",
2528
optional: false,
2629
type: factory.LiteralTypeNode.create({ value: securitySchema.in }),
2730
}),
2831
factory.PropertySignature.create({
32+
readOnly: false,
2933
name: "openIdConnectUrl",
3034
optional: false,
3135
type: factory.LiteralTypeNode.create({ value: securitySchema.openIdConnectUrl }),

src/internal/OpenApiTools/toTypeNode.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,7 @@ export const convert: Convert = (
272272

273273
const value: ts.PropertySignature[] = Object.entries(schema.properties || {}).map(([name, jsonSchema]) => {
274274
return factory.PropertySignature.create({
275+
readOnly: typeof jsonSchema !== "boolean" ? !!jsonSchema.readOnly : false,
275276
name: converterContext.escapePropertySignatureName(name),
276277
type: convert(entryPoint, currentPoint, factory, jsonSchema, context, converterContext, { parent: schema.properties }),
277278
optional: !required.includes(name),

src/internal/TsGenerator/factory/PropertySignature.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { generateComment } from "./utils";
44

55
export interface Params {
66
name: string;
7+
readOnly: boolean;
78
optional: boolean;
89
type: ts.TypeNode;
910
comment?: string;
@@ -16,8 +17,9 @@ export interface Factory {
1617
export const create =
1718
({ factory }: Pick<ts.TransformationContext, "factory">): Factory["create"] =>
1819
(params: Params): ts.PropertySignature => {
20+
1921
const node = factory.createPropertySignature(
20-
undefined,
22+
params.readOnly ? [factory.createModifier(ts.SyntaxKind.ReadonlyKeyword)] : undefined,
2123
params.name,
2224
params.optional ? factory.createToken(ts.SyntaxKind.QuestionToken) : undefined,
2325
params.type,

src/meta.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
export const Name = "@himenon/openapi-typescript-code-generator";
2-
export const Version = "0.25.0";
2+
export const Version = "0.26.1";

test/__tests__/class/__snapshots__/argo-rollout-test.ts.snap

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3827,15 +3827,15 @@ export namespace ErrorResponse {
38273827
export type RolloutService_Version = void;
38283828
}
38293829
export interface Encoding {
3830-
contentType?: string;
3830+
readonly contentType?: string;
38313831
headers?: Record<string, any>;
3832-
style?: "form" | "spaceDelimited" | "pipeDelimited" | "deepObject";
3833-
explode?: boolean;
3834-
allowReserved?: boolean;
3832+
readonly style?: "form" | "spaceDelimited" | "pipeDelimited" | "deepObject";
3833+
readonly explode?: boolean;
3834+
readonly allowReserved?: boolean;
38353835
}
38363836
export interface RequestArgs {
3837-
httpMethod: HttpMethod;
3838-
url: string;
3837+
readonly httpMethod: HttpMethod;
3838+
readonly url: string;
38393839
headers: ObjectLike | any;
38403840
requestBody?: ObjectLike | any;
38413841
requestBodyEncoding?: Record<string, Encoding>;

test/__tests__/class/__snapshots__/format.domain.ts.snap

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,15 @@ export interface QueryParameters {
4444
export type SuccessResponses = void;
4545
export namespace ErrorResponse { }
4646
export interface Encoding {
47-
contentType?: string;
47+
readonly contentType?: string;
4848
headers?: Record<string, any>;
49-
style?: "form" | "spaceDelimited" | "pipeDelimited" | "deepObject";
50-
explode?: boolean;
51-
allowReserved?: boolean;
49+
readonly style?: "form" | "spaceDelimited" | "pipeDelimited" | "deepObject";
50+
readonly explode?: boolean;
51+
readonly allowReserved?: boolean;
5252
}
5353
export interface RequestArgs {
54-
httpMethod: HttpMethod;
55-
url: string;
54+
readonly httpMethod: HttpMethod;
55+
readonly url: string;
5656
headers: ObjectLike | any;
5757
requestBody?: ObjectLike | any;
5858
requestBodyEncoding?: Record<string, Encoding>;

test/__tests__/class/__snapshots__/kubernetes-test.ts.snap

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41026,15 +41026,15 @@ export namespace ErrorResponse {
4102641026
export type getCodeVersion = void;
4102741027
}
4102841028
export interface Encoding {
41029-
contentType?: string;
41029+
readonly contentType?: string;
4103041030
headers?: Record<string, any>;
41031-
style?: "form" | "spaceDelimited" | "pipeDelimited" | "deepObject";
41032-
explode?: boolean;
41033-
allowReserved?: boolean;
41031+
readonly style?: "form" | "spaceDelimited" | "pipeDelimited" | "deepObject";
41032+
readonly explode?: boolean;
41033+
readonly allowReserved?: boolean;
4103441034
}
4103541035
export interface RequestArgs {
41036-
httpMethod: HttpMethod;
41037-
url: string;
41036+
readonly httpMethod: HttpMethod;
41037+
readonly url: string;
4103841038
headers: ObjectLike | any;
4103941039
requestBody?: ObjectLike | any;
4104041040
requestBodyEncoding?: Record<string, Encoding>;

test/__tests__/class/__snapshots__/multi-type.test.domain.ts.snap

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,15 @@ export namespace ErrorResponse {
4343
export type patchOneOf = void;
4444
}
4545
export interface Encoding {
46-
contentType?: string;
46+
readonly contentType?: string;
4747
headers?: Record<string, any>;
48-
style?: "form" | "spaceDelimited" | "pipeDelimited" | "deepObject";
49-
explode?: boolean;
50-
allowReserved?: boolean;
48+
readonly style?: "form" | "spaceDelimited" | "pipeDelimited" | "deepObject";
49+
readonly explode?: boolean;
50+
readonly allowReserved?: boolean;
5151
}
5252
export interface RequestArgs {
53-
httpMethod: HttpMethod;
54-
url: string;
53+
readonly httpMethod: HttpMethod;
54+
readonly url: string;
5555
headers: ObjectLike | any;
5656
requestBody?: ObjectLike | any;
5757
requestBodyEncoding?: Record<string, Encoding>;

0 commit comments

Comments
 (0)