@eddeee888/gcg-typescript-resolver-files
Version:
This [GraphQL Code Generator](https://www.the-guild.dev/graphql/codegen) plugin creates resolvers given GraphQL schema.
283 lines • 12.9 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseGraphQLSchema = void 0;
const tslib_1 = require("tslib");
const path = tslib_1.__importStar(require("path"));
const fs = tslib_1.__importStar(require("fs"));
const graphql_1 = require("graphql");
const utils_1 = require("../utils");
const parseLocationForOutputDir_1 = require("./parseLocationForOutputDir");
const normalizeResolverName_1 = require("./normalizeResolverName");
const parseGraphQLSchema = (_a) => tslib_1.__awaiter(void 0, [_a], void 0, function* ({ schemaAst, sourceMap, resolverTypesPath, typeMappersMap, scalarsModule, scalarsOverrides, mode, baseOutputDir, resolverRelativeTargetDir, whitelistedModules, blacklistedModules, }) {
const scalarsModuleResolverMap = scalarsModule
? yield getScalarResolverMapFromModule(scalarsModule)
: {};
return Object.entries(schemaAst.getTypeMap()).reduce((res, [schemaType, namedType]) => {
var _a, _b, _c;
if ((0, utils_1.isNativeNamedType)(namedType)) {
if ((0, graphql_1.isSpecifiedScalarType)(namedType)) {
handleNativeScalarType({ schemaType, result: res, scalarsOverrides });
}
return res;
}
// Root object types e.g. Query, Mutation, Subscription
if ((0, utils_1.isRootObjectType)(schemaType) && (0, graphql_1.isObjectType)(namedType)) {
Object.entries(namedType.getFields()).forEach(([fieldName, fieldNode]) => {
var _a;
const resolverDetails = createResolverDetails({
belongsToRootObject: schemaType,
mode,
sourceMap,
resolverRelativeTargetDir,
resolverTypesPath,
baseOutputDir,
blacklistedModules,
whitelistedModules,
schemaType,
nestedDirs: [schemaType],
location: (_a = fieldNode.astNode) === null || _a === void 0 ? void 0 : _a.loc,
resolverName: fieldName,
});
if (!resolverDetails) {
return;
}
res.userDefinedSchemaTypeMap[schemaType.toLowerCase()][resolverDetails.normalizedResolverName.withModule] =
resolverDetails;
});
return res;
}
// Wire up `mappers` config:
// - Interface
// - Enum
// - Non-root object types
if ((0, graphql_1.isInterfaceType)(namedType) ||
(0, graphql_1.isEnumType)(namedType) ||
(!(0, utils_1.isRootObjectType)(schemaType) && (0, graphql_1.isObjectType)(namedType))) {
const typeMapperDetails = typeMappersMap[schemaType];
if (typeMapperDetails) {
res.pluginsConfig.defaultTypeMappers[typeMapperDetails.schemaType] =
typeMapperDetails.configImportPath;
}
}
// Other output object types
if (!(0, utils_1.isRootObjectType)(schemaType) && (0, graphql_1.isObjectType)(namedType)) {
handleObjectType({
mode,
sourceMap,
resolverTypesPath,
resolverRelativeTargetDir,
baseOutputDir,
blacklistedModules,
whitelistedModules,
namedType,
schemaType,
result: res,
});
return res;
}
// Handle scalar type wireups
if ((0, graphql_1.isScalarType)(namedType)) {
handleScalarType({
scalarsModuleResolverMap,
schemaType,
scalarsModule,
scalarsOverrides,
result: res,
});
}
// create resolver details for other types:
// - Scalar
// - Union
// - Interface
// - Enum
const resolverDetails = createResolverDetails({
belongsToRootObject: null,
mode,
sourceMap,
resolverRelativeTargetDir,
resolverTypesPath,
baseOutputDir,
blacklistedModules,
whitelistedModules,
schemaType,
nestedDirs: [],
location: (_a = namedType.astNode) === null || _a === void 0 ? void 0 : _a.loc,
resolverName: namedType.name,
});
if (resolverDetails) {
if ((0, graphql_1.isScalarType)(namedType)) {
res.userDefinedSchemaTypeMap.scalar[schemaType] = resolverDetails;
}
else if ((0, graphql_1.isUnionType)(namedType)) {
res.userDefinedSchemaTypeMap.union[schemaType] = resolverDetails;
}
else if ((0, graphql_1.isInterfaceType)(namedType)) {
res.userDefinedSchemaTypeMap.interface[schemaType] = resolverDetails;
}
else if ((0, graphql_1.isEnumType)(namedType)) {
res.userDefinedSchemaTypeMap.enum[schemaType] = Object.assign(Object.assign({}, resolverDetails), { allowedValues: ((_c = (_b = namedType.astNode) === null || _b === void 0 ? void 0 : _b.values) === null || _c === void 0 ? void 0 : _c.map((v) => v.name.value)) || [] });
}
}
return res;
}, {
userDefinedSchemaTypeMap: {
query: {},
mutation: {},
subscription: {},
object: {},
scalar: {},
interface: {},
union: {},
enum: {},
},
pluginsConfig: {
defaultScalarTypesMap: {},
scalarsModuleResolvers: {},
unmanagedScalarResolvers: {},
defaultTypeMappers: {},
},
});
});
exports.parseGraphQLSchema = parseGraphQLSchema;
const handleScalarType = ({ scalarsModuleResolverMap, schemaType, scalarsModule, scalarsOverrides, result, }) => {
const scalarsModuleResolver = scalarsModuleResolverMap[schemaType];
// Use found the scalar from scalar module
if (scalarsModuleResolver) {
if (scalarsModuleResolver.extensions.codegenScalarType &&
typeof scalarsModuleResolver.extensions.codegenScalarType === 'string') {
result.pluginsConfig.defaultScalarTypesMap[schemaType] =
scalarsModuleResolver.extensions.codegenScalarType;
}
result.pluginsConfig.scalarsModuleResolvers[schemaType] = `~${scalarsModule}#${scalarsModuleResolver.name}Resolver`;
}
// If found scalar overrides, use them
const override = scalarsOverrides[schemaType];
if (override) {
if (override.type) {
result.pluginsConfig.defaultScalarTypesMap[schemaType] = override.type;
}
if (override.resolver) {
result.pluginsConfig.unmanagedScalarResolvers[schemaType] =
override.resolver;
}
}
};
const getScalarResolverMapFromModule = (scalarsModule) => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
let module;
try {
module = yield Promise.resolve(`${scalarsModule}`).then(s => tslib_1.__importStar(require(s)));
}
catch (err) {
if (err instanceof Error &&
'code' in err &&
err.code === 'MODULE_NOT_FOUND') {
utils_1.logger.warn(`Unable to import \`${scalarsModule}\`. Install \`${scalarsModule}\` or you have to implement Scalar resolvers by yourself.`);
}
}
if (!module || !module.resolvers) {
return {};
}
return module.resolvers;
});
const handleNativeScalarType = ({ schemaType, result, scalarsOverrides, }) => {
const override = scalarsOverrides[schemaType];
// Note: only override the type i.e. same functionality as `typescript` plugin's scalars
// I've never seen someone overriding native scalar's implementation so it's probably not a thing.
if (override && override.type) {
result.pluginsConfig.defaultScalarTypesMap[schemaType] = override.type;
}
};
const handleObjectType = ({ mode, sourceMap, resolverTypesPath, resolverRelativeTargetDir, baseOutputDir, blacklistedModules, whitelistedModules, namedType, schemaType, result, }) => {
// parse for details
const fieldsByGraphQLModule = Object.entries(namedType.getFields()).reduce((res, [_, fieldNode]) => {
var _a;
const fieldLocation = (_a = fieldNode.astNode) === null || _a === void 0 ? void 0 : _a.loc;
const modulePath = path.dirname((fieldLocation === null || fieldLocation === void 0 ? void 0 : fieldLocation.source.name) || '');
if (!res[modulePath]) {
res[modulePath] = {
fieldNodes: [],
// Note: fieldLocation here is the location of the first field found in a GraphQL Module.
// The reason we use field's location instead of the object type's location is because when `extend type ObjectType` is used, the location of object type is the last found location.
// i.e. we cannot rely on object's location if `extend type` is used.
firstFieldLocation: fieldLocation,
};
}
res[modulePath].fieldNodes.push(fieldNode);
return res;
}, {});
result.userDefinedSchemaTypeMap.object[schemaType] =
result.userDefinedSchemaTypeMap.object[schemaType] || {};
Object.entries(fieldsByGraphQLModule).forEach(([_modulePath, { firstFieldLocation, fieldNodes }], _index, graphQLModules) => {
const resolverDetails = createResolverDetails({
belongsToRootObject: null,
mode,
sourceMap,
resolverRelativeTargetDir,
resolverTypesPath,
baseOutputDir,
blacklistedModules,
whitelistedModules,
schemaType,
nestedDirs: [],
location: firstFieldLocation,
resolverName: namedType.name,
});
if (!resolverDetails) {
return;
}
// If there are multiple object type files to generate
// e.g. `extend type ObjectType` is used across multiple modules
// We create an array of fields to pick for each module
//
// If there's only one module, we return an empty array i.e. pick all fields
const fieldsToPick = graphQLModules.length > 1 ? fieldNodes.map((field) => field.name) : [];
result.userDefinedSchemaTypeMap.object[schemaType][resolverDetails.normalizedResolverName.withModule] = Object.assign(Object.assign({}, resolverDetails), { fieldsToPick });
});
};
const createResolverDetails = ({ belongsToRootObject, mode, sourceMap, resolverRelativeTargetDir, resolverTypesPath, baseOutputDir, blacklistedModules, whitelistedModules, schemaType, nestedDirs, location, resolverName, }) => {
const parsedDetails = (0, parseLocationForOutputDir_1.parseLocationForOutputDir)({
nestedDirs,
location,
mode,
sourceMap,
resolverRelativeTargetDir,
baseOutputDir,
blacklistedModules,
whitelistedModules,
});
if (!parsedDetails) {
// No `parsedDetails` means the location is NOT whitelisted, ignore.
return;
}
const { moduleName, resolversOutputDir, relativePathFromBaseToModule } = parsedDetails;
const normalizedResolverName = (0, normalizeResolverName_1.normalizeResolverName)(moduleName, resolverName, belongsToRootObject);
const resolverFilePath = path.posix.join(resolversOutputDir, `${resolverName}.ts`);
return {
schemaType,
moduleName,
resolverFile: {
name: resolverName,
path: resolverFilePath,
isOnFilesystem: fs.existsSync(resolverFilePath),
},
relativePathFromBaseToModule,
normalizedResolverName,
typeNamedImport: ({ generatedResolverTypes }) => {
var _a;
return ((_a = generatedResolverTypes.userDefined[schemaType]) === null || _a === void 0 ? void 0 : _a.name) ||
`${schemaType}Resolvers`;
},
typeString: ({ generatedResolverTypes }) => {
var _a;
if (belongsToRootObject) {
return generatedResolverTypes.userDefined[schemaType]
? `${generatedResolverTypes.userDefined[schemaType].name}['${resolverName}']`
: `${schemaType}Resolvers['${resolverName}']`;
}
return (((_a = generatedResolverTypes.userDefined[schemaType]) === null || _a === void 0 ? void 0 : _a.name) ||
`${schemaType}Resolvers`);
},
relativePathToResolverTypesFile: (0, utils_1.relativeModulePath)(resolversOutputDir, resolverTypesPath),
};
};
//# sourceMappingURL=parseGraphQLSchema.js.map
;