Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/test-pr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ jobs:
- javascript,schema-javascript
- golang,schema-golang
- cjson,schema-cjson
- cjson-default,cjson-multi-header,cjson-multi-split
- cplusplus,schema-cplusplus
- flow,schema-flow
- java,schema-java
Expand Down
4 changes: 1 addition & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@ test/golang/schema-from-schema.json
test/elm/elm-stuff/
test/elm/elm.js
test/elm/QuickType.elm
test/fixtures/cjson/cJSON.*
test/fixtures/cjson/hashtable.*
test/fixtures/cjson/list.*
test/fixtures/cjson/deps/
test/fixtures/rust/target
test/fixtures/java/target
test/fixtures/java-lombok/target
Expand Down
208 changes: 159 additions & 49 deletions packages/quicktype-core/src/language/CJSON/CJSONRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,13 @@ import {
} from "./utils.js";

export class CJSONRenderer extends ConvenienceRenderer {
private currentFilename: string | undefined; /* Current filename */
private currentHeaderFilename:
| string
| undefined; /* Current header filename */

private currentSourceFilename:
| string
| undefined; /* Current source filename */

private readonly memberNameStyle: NameStyle; /* Member name style */

Expand Down Expand Up @@ -231,8 +237,8 @@ export class CJSONRenderer extends ConvenienceRenderer {
}

/**
* Function called to create header file(s)
* @param proposedFilename: source filename provided from stdin
* Function called to create header and source file(s)
* @param proposedFilename: source filename provided from stdin (without extensions)
*/
protected emitSourceStructure(proposedFilename: string): void {
/* Depending of source style option, generate a unique header or multiple header files */
Expand All @@ -244,12 +250,12 @@ export class CJSONRenderer extends ConvenienceRenderer {
}

/**
* Function called to create a single header file with types and generators
* Function called to create a single pair of header/source files with types and generators
* @param proposedFilename: source filename provided from stdin
*/
protected emitSingleSourceStructure(proposedFilename: string): void {
/* Create file */
this.startFile(proposedFilename);
/* Create header file */
this.startHeaderFile(proposedFilename);

/* Create types */
this.forEachDeclaration("leading-and-interposing", (decl) => {
Expand Down Expand Up @@ -306,6 +312,14 @@ export class CJSONRenderer extends ConvenienceRenderer {
(type) => this.namedTypeToNameForTopLevel(type) === undefined,
);

if (!this._options.headerOnly) {
/* Close header file */
this.finishHeaderFile();

/* Create source file */
this.startSourceFile(proposedFilename);
}

/* Create enum functions */
this.forEachEnum(
"leading-and-interposing",
Expand Down Expand Up @@ -333,8 +347,7 @@ export class CJSONRenderer extends ConvenienceRenderer {
(type) => this.namedTypeToNameForTopLevel(type) === undefined,
);

/* Close file */
this.finishFile();
this.finishCurrentFile();
}

/**
Expand Down Expand Up @@ -371,24 +384,31 @@ export class CJSONRenderer extends ConvenienceRenderer {
protected emitEnum(enumType: EnumType): void {
/* Create file */
const enumName = this.nameForNamedType(enumType);
const filename = this.sourcelikeToString(enumName).concat(".h");
this.includes.push(filename);
this.startFile(filename);
const headerFilename = this.sourcelikeToString(enumName).concat(".h");
this.includes.push(headerFilename);
this.startHeaderFile(headerFilename);

/* Create includes */
this.emitIncludes(enumType, this.sourcelikeToString(filename));
this.emitIncludes(enumType, this.sourcelikeToString(headerFilename));

/* Create types */
this.emitEnumTypedef(enumType);

/* Create prototypes */
this.emitEnumPrototypes(enumType);

if (!this._options.headerOnly) {
/* Close header file */
this.finishHeaderFile();

/* Create source file */
this.startSourceFile(headerFilename);
}

/* Create functions */
this.emitEnumFunctions(enumType);

/* Close file */
this.finishFile();
this.finishCurrentFile();
}

/**
Expand Down Expand Up @@ -548,24 +568,31 @@ export class CJSONRenderer extends ConvenienceRenderer {
protected emitUnion(unionType: UnionType): void {
/* Create file */
const unionName = this.nameForNamedType(unionType);
const filename = this.sourcelikeToString(unionName).concat(".h");
this.includes.push(filename);
this.startFile(filename);
const headerFilename = this.sourcelikeToString(unionName).concat(".h");
this.includes.push(headerFilename);
this.startHeaderFile(headerFilename);

/* Create includes */
this.emitIncludes(unionType, this.sourcelikeToString(filename));
this.emitIncludes(unionType, this.sourcelikeToString(headerFilename));

/* Create types */
this.emitUnionTypedef(unionType);

/* Create prototypes */
this.emitUnionPrototypes(unionType);

if (!this._options.headerOnly) {
/* Close header file */
this.finishHeaderFile();

/* Create source file */
this.startSourceFile(headerFilename);
}

/* Create functions */
this.emitUnionFunctions(unionType);

/* Close file */
this.finishFile();
this.finishCurrentFile();
}

/**
Expand Down Expand Up @@ -1991,24 +2018,31 @@ export class CJSONRenderer extends ConvenienceRenderer {
protected emitClass(classType: ClassType): void {
/* Create file */
const className = this.nameForNamedType(classType);
const filename = this.sourcelikeToString(className).concat(".h");
this.includes.push(filename);
this.startFile(filename);
const headerFilename = this.sourcelikeToString(className).concat(".h");
this.includes.push(headerFilename);
this.startHeaderFile(headerFilename);

/* Create includes */
this.emitIncludes(classType, this.sourcelikeToString(filename));
this.emitIncludes(classType, this.sourcelikeToString(headerFilename));

/* Create types */
this.emitClassTypedef(classType);

/* Create prototypes */
this.emitClassPrototypes(classType);

if (!this._options.headerOnly) {
/* Close header file */
this.finishHeaderFile();

/* Create source file */
this.startSourceFile(headerFilename);
}

/* Create functions */
this.emitClassFunctions(classType);

/* Close file */
this.finishFile();
this.finishCurrentFile();
}

/**
Expand Down Expand Up @@ -4598,8 +4632,8 @@ export class CJSONRenderer extends ConvenienceRenderer {
includes: string[],
): void {
/* Create file */
const filename = this.sourcelikeToString(className).concat(".h");
this.startFile(filename);
const headerFilename = this.sourcelikeToString(className).concat(".h");
this.startHeaderFile(headerFilename);

/* Create includes - This create too much includes but this is safer because of specific corner cases */
includes.forEach((name) => {
Expand All @@ -4613,11 +4647,18 @@ export class CJSONRenderer extends ConvenienceRenderer {
/* Create prototypes */
this.emitTopLevelPrototypes(type, className);

if (!this._options.headerOnly) {
/* Close header file */
this.finishHeaderFile();

/* Create source file */
this.startSourceFile(headerFilename);
}

/* Create functions */
this.emitTopLevelFunctions(type, className);

/* Close file */
this.finishFile();
this.finishCurrentFile();
}

/**
Expand Down Expand Up @@ -5535,24 +5576,25 @@ export class CJSONRenderer extends ConvenienceRenderer {
}

/**
* Function called to create a file
* Function called to create a header file
* @param proposedFilename: source filename provided from stdin
*/
protected startFile(proposedFilename: Sourcelike): void {
/* Check if previous file is closed, create a new file */
protected startHeaderFile(proposedFilename: Sourcelike): void {
/* Check if previous header file is closed, create a new file */
assert(
this.currentFilename === undefined,
"Previous file wasn't finished",
this.currentHeaderFilename === undefined,
"Previous header file wasn't finished",
);
if (proposedFilename !== undefined) {
this.currentFilename = this.sourcelikeToString(proposedFilename);
this.currentHeaderFilename =
this.sourcelikeToString(proposedFilename);
}

/* Check if file has been created */
if (this.currentFilename !== undefined) {
/* Check if header file has been created */
if (this.currentHeaderFilename !== undefined) {
/* Write header */
this.emitDescriptionBlock([
this.currentFilename,
this.currentHeaderFilename,
"This file has been autogenerated using quicktype https://github.com/quicktype/quicktype - DO NOT EDIT",
"This file depends of https://github.com/DaveGamble/cJSON, https://github.com/joelguittet/c-list and https://github.com/joelguittet/c-hashtable",
"To parse json data from json string use the following: struct <type> * data = cJSON_Parse<type>(<string>);",
Expand All @@ -5567,7 +5609,7 @@ export class CJSONRenderer extends ConvenienceRenderer {
this.emitLine(
"#ifndef __",
allUpperWordStyle(
this.currentFilename.replace(
this.currentHeaderFilename.replace(
new RegExp(/[^a-zA-Z0-9]+/, "g"),
"_",
),
Expand All @@ -5577,7 +5619,7 @@ export class CJSONRenderer extends ConvenienceRenderer {
this.emitLine(
"#define __",
allUpperWordStyle(
this.currentFilename.replace(
this.currentHeaderFilename.replace(
new RegExp(/[^a-zA-Z0-9]+/, "g"),
"_",
),
Expand Down Expand Up @@ -5617,11 +5659,42 @@ export class CJSONRenderer extends ConvenienceRenderer {
}

/**
* Function called to close current file
* Function called to create a source file
* @param headerFilename: filename of the header file corresponding to this source file
*/
protected startSourceFile(headerFilename: Sourcelike): void {
/* Check if previous source file is closed, create a new file */
assert(
this.currentSourceFilename === undefined,
"Previous source file wasn't finished",
);
if (headerFilename !== undefined) {
this.currentSourceFilename = this.getSourceNameFromHeaderName(
this.sourcelikeToString(headerFilename),
);
}

/* Check if source file has been created */
if (this.currentSourceFilename !== undefined) {
/* Write header */
this.emitDescriptionBlock([
this.currentSourceFilename,
"This file has been autogenerated using quicktype https://github.com/quicktype/quicktype - DO NOT EDIT",
]);
this.ensureBlankLine();

/* Include corresponding header file */
this.emitIncludeLine(this.sourcelikeToString(headerFilename));
this.ensureBlankLine();
}
}

/**
* Function called to close current header file
*/
protected finishFile(): void {
/* Check if file has been created */
if (this.currentFilename !== undefined) {
protected finishHeaderFile(): void {
/* Check if header file has been created */
if (this.currentHeaderFilename !== undefined) {
/* Write C++ guard */
this.emitLine("#ifdef __cplusplus");
this.emitLine("}");
Expand All @@ -5632,7 +5705,7 @@ export class CJSONRenderer extends ConvenienceRenderer {
this.emitLine(
"#endif /* __",
allUpperWordStyle(
this.currentFilename.replace(
this.currentHeaderFilename.replace(
new RegExp(/[^a-zA-Z0-9]+/, "g"),
"_",
),
Expand All @@ -5641,9 +5714,37 @@ export class CJSONRenderer extends ConvenienceRenderer {
);
this.ensureBlankLine();

/* Close file */
super.finishFile(defined(this.currentFilename));
this.currentFilename = undefined;
/* Close header file */
super.finishFile(defined(this.currentHeaderFilename));
this.currentHeaderFilename = undefined;
}
}

/**
* Function called to close current source file
*/
protected finishSourceFile(): void {
/* Check if source file has been created */
if (this.currentSourceFilename !== undefined) {
this.ensureBlankLine();

/* Close source file */
super.finishFile(defined(this.currentSourceFilename));
this.currentSourceFilename = undefined;
}
}

/**
* Function called to close the current file, either the header file when
* generating headers only, or the source file otherwise
*/
protected finishCurrentFile(): void {
if (this._options.headerOnly) {
/* Close header file */
this.finishHeaderFile();
} else {
/* Close source file */
this.finishSourceFile();
}
}

Expand Down Expand Up @@ -5909,4 +6010,13 @@ export class CJSONRenderer extends ConvenienceRenderer {
recur(false, false, 0, type);
return result;
}

/**
* Get the name of the source file corresponding to a header file
* @param headerName: header filename
* @return Source filename
*/
protected getSourceNameFromHeaderName(headerName: string): string {
return headerName.replace(/\.h$/, ".c");
}
}
Loading
Loading