UNPKG

graphql-codegen-faker-fixtures

Version:

Generate faker fixtures for your fields

337 lines (330 loc) 12.8 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var src_exports = {}; __export(src_exports, { plugin: () => plugin }); module.exports = __toCommonJS(src_exports); // src/plugin.ts var import_graphql = require("graphql"); var import_plugin_helpers = require("@graphql-codegen/plugin-helpers"); var pluginConfig; var plugin = (schema, documents, config) => { pluginConfig = config; const { typeImport, skipFragments, buildersOnly, fakerjsSeed } = pluginConfig; const disclaimer = ` /* NOTE: This file is auto-generated. DO NOT EDIT. */ `; const imports = [ `import * as types from '${typeImport || "CONFIGURE_TYPE_IMPORT"}';`, `import { deepmergeCustom } from 'deepmerge-ts'`, `import { faker } from '@faker-js/faker';` ].join("\n"); const utils = ` export type DeepPartial<T> = T extends object ? { [P in keyof T]?: DeepPartial<T[P]> } : T export const repeat = <T>(numTimes: number, callback: (i: number) => T) => Array.from(Array(numTimes).keys()).map((i) => callback(i)) const deepmerge = deepmergeCustom({ mergeArrays: false }) export const merge = <T>(fixture: T, override: unknown) => deepmerge(fixture, override) as T export const random = (min: number, max: number) => faker.number.int({ min, max }) faker.seed(${fakerjsSeed || 12345654321}) `; const astSchema = (0, import_graphql.parse)((0, import_graphql.printSchema)(schema)); const documentNodes = documents.map((document) => document.document).filter(Boolean); const { enums, fields, unions } = collectFromSchema(astSchema); const fragments = documentNodes.flatMap( (documentNode) => collectFragments(documentNode, fields) ); const code = fragments.filter((fragment) => !(skipFragments == null ? void 0 : skipFragments.includes(fragment.fragmentName))).map((fragment) => createFragmentBuilder(fragment, enums, unions)).join("\n"); const parts = buildersOnly ? [code] : [disclaimer, imports, utils, code]; return parts.join("\n\n"); }; var collectFromSchema = (astNode) => { const fields = []; const enums = []; const unions = []; const visitObjectTypeOrInterfaceType = (node) => { var _a; const objectName = node.name.value; (_a = node == null ? void 0 : node.fields) == null ? void 0 : _a.forEach((field) => { const fieldName = field.name.value; const fieldType = collectFieldType(field.type); const isArray = field.type.kind === import_graphql.Kind.NON_NULL_TYPE ? field.type.type.kind === import_graphql.Kind.LIST_TYPE : field.type.kind === import_graphql.Kind.LIST_TYPE; fields.push({ objectName, fieldType, fieldName, isArray }); }); }; (0, import_graphql.visit)(astNode, { EnumTypeDefinition: { leave: (node) => { var _a; const enumName = node.name.value; const enumValues = ((_a = node == null ? void 0 : node.values) == null ? void 0 : _a.map((value) => value.name.value)) || []; enums.push({ enumName, enumValues }); } }, // Gets called every time the visitor visits an UnionTypeDefinition UnionTypeDefinition: { leave: (node) => { var _a; const unionName = node.name.value; const unionValues = ((_a = node.types) == null ? void 0 : _a.map((namedTypeNode) => namedTypeNode.name.value)) || []; unions.push({ unionName, unionValues }); } }, // Gets called every time the visitor visits an ObjectTypeDefinition ObjectTypeDefinition: { leave: visitObjectTypeOrInterfaceType }, // Gets called every time the visitor visits an InterfaceTypeDefinition InterfaceTypeDefinition: { leave: visitObjectTypeOrInterfaceType } }); return { fields, enums, unions }; }; var collectFieldType = (node) => { if (node.kind === import_graphql.Kind.NON_NULL_TYPE || node.kind === import_graphql.Kind.LIST_TYPE) { return collectFieldType(node.type); } return node.name.value; }; var collectFragments = (astNode, collectedFields) => { const fragments = []; const collectFieldsInFragment = (node, objectName) => { const fields = []; node.selections.map((selection) => { var _a, _b; if (selection.kind === import_graphql.Kind.FIELD) { const fieldName = selection.name.value; const collectedField = fieldName === "__typename" ? ( // We have encountered a '__typename' field. // These are special as they should have a hardcoded value: objectName { fieldType: "__typename", fieldName: "__typename", objectName } ) : ( // field was not a __typename. // Let's see if we can find the Field we have collected earlier. // It should contain more info on its type. collectedFields.find( (collectedField2) => collectedField2.objectName === objectName && collectedField2.fieldName === fieldName ) ); if (!collectedField) { throw new Error( `Could not find type for field ${fieldName} in fragment for ${objectName}` ); } let field = { ...collectedField }; const fieldAlias = (_a = selection.alias) == null ? void 0 : _a.value; if (fieldAlias) { field = { ...field, fieldName: fieldAlias }; } if (selection.selectionSet) { field = { ...field, fields: collectFieldsInFragment( selection.selectionSet, field.fieldType ) }; } fields.push(field); } else if (selection.kind === import_graphql.Kind.FRAGMENT_SPREAD) { fields.push({ spreadName: selection.name.value, isSpread: true, fieldName: "", fieldType: "", objectName: "" }); } else if (selection.kind === import_graphql.Kind.INLINE_FRAGMENT) { const objectName2 = ((_b = selection.typeCondition) == null ? void 0 : _b.name.value) || ""; fields.push({ fieldName: "", fieldType: "", objectName: objectName2, isSpread: true, fields: collectFieldsInFragment(selection.selectionSet, objectName2) }); } }); return fields; }; (0, import_graphql.visit)(astNode, { FragmentDefinition: { leave: (node) => { const fragmentName = node.name.value; const objectName = node.typeCondition.name.value; const fields = collectFieldsInFragment(node.selectionSet, objectName); fragments.push({ fragmentName, objectName, fields }); } } }); return fragments; }; var convertToCorrectCaseType = (fragmentName) => { const { namingConvention } = pluginConfig; if (!namingConvention) { return (0, import_plugin_helpers.resolveExternalModuleAndFn)("change-case-all#pascalCase")( fragmentName ); } if (namingConvention === "keep") { return fragmentName; } return (0, import_plugin_helpers.resolveExternalModuleAndFn)(namingConvention)(fragmentName); }; var createFragmentBuilder = (fragment, enums, unions) => { const name = fragment.fragmentName; const casedName = convertToCorrectCaseType(name); const typeName = `types.${casedName}Fragment`; const partialTypeName = `DeepPartial<${typeName}>`; const isUnion = unions.some( (union) => union.unionName === fragment.objectName ); if (isUnion) { return ` export const fake${casedName} = ():${typeName} => faker.helpers.arrayElement([ ${fragment.fields.filter((field) => field.spreadName).map((field) => convertToCorrectCaseType(field.spreadName || "")).map((casedName2) => `fake${casedName2}()`).join(",")} ]) `; } return ` export const fake${casedName} = (override?:${partialTypeName}):${typeName} => { const fixture:${typeName} = { ${createFakerFields(fragment.fields, enums, casedName)} } return override ? merge(fixture, override) : fixture } `; }; var createFakerFields = (fields, enums, casedName) => { const { skipFields } = pluginConfig; const shouldSkipField = (fieldName) => skipFields == null ? void 0 : skipFields.includes(`${casedName}Fragment.${fieldName}`); const nonSpreads = fields.filter((field) => !field.isSpread); const spreads = fields.filter((field) => field.isSpread); const nonSpreadString = nonSpreads.filter((field) => !shouldSkipField(field.fieldName)).map((field) => createFakerValue(field, enums, casedName)).join(","); const spreadValues = spreads.filter((field) => !shouldSkipField(field.fieldName)).map((field) => createFakerValue(field, enums, casedName)); let spreadString = ""; if (spreadValues.length === 1) { spreadString = `...${spreadValues[0]}`; } else if (spreadValues.length > 1) { spreadString = `...faker.helpers.arrayElement([${spreadValues.join(",")}])`; } return [nonSpreadString, spreadString].filter(Boolean).join(","); }; var createFakerValue = (field, enums, casedName) => { if (field.fieldName === "__typename") { return `__typename: '${field.objectName}'`; } const prefix = field.isArray ? "repeat(random(1 , 5), () => (" : ""; const suffix = field.isArray ? "))" : ""; if (field.spreadName) { const fragmentName = convertToCorrectCaseType(field.spreadName); return `${prefix}fake${fragmentName}()${suffix}`; } if (field.fields && field.isSpread && !field.spreadName) { const subFields = createFakerFields(field.fields, enums, casedName); return `${prefix}{${subFields}}${suffix}`; } if (field.fields) { if (field.fields.length === 0) { throw new Error("Field should have subFields"); } const subFields = createFakerFields(field.fields, enums, casedName); return `${field.fieldName}: ${prefix}{ ${subFields} }${suffix}`; } const fakerMethod = createFakerMethod(field, enums); if (fakerMethod) { return `${field.fieldName}: ${prefix}${fakerMethod}${suffix}`; } return ""; }; var findFakerMethodOfScalar = (scalar, defaultMethod, field) => { var _a; const { scalars } = pluginConfig; const scalarConfig = scalars == null ? void 0 : scalars[scalar]; const defaultFieldMethod = ((_a = scalars == null ? void 0 : scalars[scalar]) == null ? void 0 : _a._default) || defaultMethod; if (!scalarConfig) { return defaultFieldMethod; } if (`${field.objectName}.${field.fieldName}` in scalarConfig) { if (typeof scalarConfig[`${field.objectName}.${field.fieldName}`] !== "string") { throw Error( `Configuration error: value of ${field.objectName}.${field.fieldName} in ${scalar} is not of type "string".` ); } return scalarConfig[`${field.objectName}.${field.fieldName}`]; } if (field.fieldName in scalarConfig) { if (typeof scalarConfig[field.fieldName] !== "string") { throw Error( `Configuration error: value of ${field.fieldName} in ${scalar} is not of type "string".` ); } return scalarConfig[field.fieldName]; } return defaultFieldMethod; }; var findFieldAsExistingEnum = (field, enums) => { return enums.find((myEnum) => myEnum.enumName === field.fieldType); }; var findDefaultFakerMethodForScalar = (scalar) => { switch (scalar) { case "Int": return "faker.number.int()"; case "Float": return "faker.number.float()"; case "Boolean": return "faker.datatype.boolean()"; case "ID": return "faker.string.uuid()"; case "String": default: return "faker.lorem.words()"; } }; var createFakerMethod = (field, enums) => { const myEnum = findFieldAsExistingEnum(field, enums); if (myEnum) { return `faker.helpers.arrayElement(${JSON.stringify(myEnum.enumValues)})`; } else { return findFakerMethodOfScalar(field.fieldType, findDefaultFakerMethodForScalar(field.fieldType), field); } }; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { plugin }); //# sourceMappingURL=index.js.map