Generated GraphQL SDL from Concerto CTO models is written by GraphQLVisitor (lib/codegen/fromcto/graphql/graphqlvisitor.js). Today, npm test only checks snapshots, it does not run a GraphQL parser on the output.
When you compile with graphql-js parse() standard repo fixtures produce invalid SDL.
Related: bug: JSON Schema verification bugs (generated output fails Ajv) #240
Bug 1: Empty enum in hr_base.cto
Cause
hr_base.cto defines an empty enum:
For types with no properties, GraphQLVisitor emits a placeholder field _: Boolean (see graphql/graphql-spec#568). That works for object types, but for an empty enum the visitor emits:
enum Level {
_: Boolean
}
_: Boolean is object field syntax, not a valid enum value. graphql-js parse() fails on this SDL.
Reproduce
From the repo root (after npm ci):
node -e "
const fs = require('fs');
const path = require('path');
const { parse } = require('graphql');
const { dir } = require('tmp-promise');
const { ModelManager } = require('@accordproject/concerto-core');
const { FileWriter } = require('@accordproject/concerto-util');
const GraphQLVisitor = require('./lib/codegen/fromcto/graphql/graphqlvisitor.js');
process.env.ENABLE_MAP_TYPE = 'true';
process.env.IMPORT_ALIASING = 'true';
(async () => {
const mm = new ModelManager();
mm.addCTOModel(
fs.readFileSync('./test/codegen/fromcto/data/model/hr_base.cto', 'utf8'),
'hr_base.cto'
);
const { path: out, cleanup } = await dir({ unsafeCleanup: true });
mm.accept(new GraphQLVisitor(), { fileWriter: new FileWriter(out) });
const sdl = fs.readFileSync(path.join(out, 'model.gql'), 'utf8');
parse(sdl);
console.log('OK');
await cleanup();
})().catch((err) => {
console.error(err.message);
process.exit(1);
});
"
Expected error
Syntax Error: Expected Name, found ":".
Generated fragment
enum Level {
_: Boolean
}
Bug 2: Custom scalars not emitted in hr_base.cto + hr.cto
Cause
hr_base.cto defines Concerto scalars such as SSN and Time. hr.cto also references types like KinName, KinTelephone, and Concept. The visitor uses these names in field and map type definitions but does not emit corresponding scalar (or type) declarations in the SDL.
With both HR fixtures loaded (same pair as test/codegen/codegen.js), the generated SDL references undefined types. graphql-js parse() accepts the syntax, but buildSchema() fails when building a schema from the output.
Note: Bug 1 must be worked around first (empty Level enum) to reach this failure. Remove or fix the enum Level { ... } block in the generated SDL before calling buildSchema().
Reproduce
node -e "
const fs = require('fs');
const path = require('path');
const { buildSchema } = require('graphql');
const { dir } = require('tmp-promise');
const { ModelManager } = require('@accordproject/concerto-core');
const { FileWriter } = require('@accordproject/concerto-util');
const GraphQLVisitor = require('./lib/codegen/fromcto/graphql/graphqlvisitor.js');
process.env.ENABLE_MAP_TYPE = 'true';
process.env.IMPORT_ALIASING = 'true';
const MODEL_DIR = './test/codegen/fromcto/data/model';
(async () => {
const mm = new ModelManager();
mm.addCTOModel(fs.readFileSync(path.join(MODEL_DIR, 'hr_base.cto'), 'utf8'), 'hr_base.cto');
mm.addCTOModel(fs.readFileSync(path.join(MODEL_DIR, 'hr.cto'), 'utf8'), 'hr.cto');
const { path: out, cleanup } = await dir({ unsafeCleanup: true });
mm.accept(new GraphQLVisitor(), {
fileWriter: new FileWriter(out),
showCompositionRelationships: true,
});
let sdl = fs.readFileSync(path.join(out, 'model.gql'), 'utf8');
// Work around Bug 1 so we can validate type references
sdl = sdl.replace(/enum Level \{[^}]+\}\n?/, 'enum Level { PLACEHOLDER }\n');
buildSchema(sdl);
console.log('OK');
await cleanup();
})().catch((err) => {
console.error(err.message);
process.exit(1);
});
"
Expected error
Unknown type "SSN".
Unknown type "Time".
(Additional errors for KinName, KinTelephone, Concept, and invalid directive locations on enums may also appear.)
Example generated references without definitions
type EmployeeTShirtSizes {
key: SSN
value: TShirtSizeType
}
type EmployeeDirectory {
key: SSN
value: Employee
}
map fields also reference Time, KinName, KinTelephone, Concept
Only scalar DateTime is declared in the generated output; SSN, Time, and other custom types are not.
Related code
| File |
Role |
lib/codegen/fromcto/graphql/graphqlvisitor.js |
Emits GraphQL SDL (visitMapDeclaration, empty-type _: Boolean placeholder) |
test/codegen/codegen.js |
Snapshot tests (no GraphQL parser on output) |
test/codegen/fromcto/graphql/graphqlvisitor.js |
Unit tests with mocked FileWriter, not full HR fixtures |
Generated GraphQL SDL from Concerto CTO models is written by
GraphQLVisitor(lib/codegen/fromcto/graphql/graphqlvisitor.js). Today,npm testonly checks snapshots, it does not run a GraphQL parser on the output.When you compile with graphql-js
parse()standard repo fixtures produce invalid SDL.Related: bug: JSON Schema verification bugs (generated output fails Ajv) #240
Bug 1: Empty enum in
hr_base.ctoCause
hr_base.ctodefines an empty enum:For types with no properties,
GraphQLVisitoremits a placeholder field_: Boolean(see graphql/graphql-spec#568). That works for object types, but for an empty enum the visitor emits:_: Booleanis object field syntax, not a valid enum value.graphql-jsparse()fails on this SDL.Reproduce
From the repo root (after
npm ci):Expected error
Generated fragment
Bug 2: Custom scalars not emitted in
hr_base.cto+hr.ctoCause
hr_base.ctodefines Concerto scalars such asSSNandTime.hr.ctoalso references types likeKinName,KinTelephone, andConcept. The visitor uses these names in field and map type definitions but does not emit correspondingscalar(ortype) declarations in the SDL.With both HR fixtures loaded (same pair as
test/codegen/codegen.js), the generated SDL references undefined types.graphql-jsparse()accepts the syntax, butbuildSchema()fails when building a schema from the output.Reproduce
Expected error
(Additional errors for
KinName,KinTelephone,Concept, and invalid directive locations on enums may also appear.)Example generated references without definitions
Only
scalar DateTimeis declared in the generated output;SSN,Time, and other custom types are not.Related code
lib/codegen/fromcto/graphql/graphqlvisitor.jsvisitMapDeclaration, empty-type_: Booleanplaceholder)test/codegen/codegen.jstest/codegen/fromcto/graphql/graphqlvisitor.jsFileWriter, not full HR fixtures