UNPKG

@graphql-codegen/visitor-plugin-common

Version:
160 lines (159 loc) • 6.95 kB
import { DeclarationBlock, indent, transformComment, getNodeComment, wrapWithSingleQuotes, } from './utils.js'; export const convertSchemaEnumToDeclarationBlockString = ({ schema, node, enumName, enumValues, futureProofEnums, ignoreEnumValuesFromSchema, outputType, declarationBlockConfig, naming, }) => { if (enumValues[enumName]?.sourceFile) { return `export { ${enumValues[enumName].typeIdentifier} };\n`; } const getValueFromConfig = (enumValue) => { if (typeof enumValues[enumName]?.mappedValues?.[enumValue] !== 'undefined') { return enumValues[enumName].mappedValues[enumValue]; } return null; }; const withFutureAddedValue = [futureProofEnums ? [indent('| ' + wrapWithSingleQuotes('%future added value'))] : []]; const enumTypeName = convertName({ options: { typesPrefix: naming.typesPrefix, typesSuffix: naming.typesSuffix, useTypesPrefix: naming.useTypesPrefix, useTypesSuffix: naming.useTypesSuffix, }, convert: () => naming.convert(node), }); if (outputType === 'string-literal') { return new DeclarationBlock(declarationBlockConfig) .export() .asKind('type') .withComment(node.description?.value) .withName(enumTypeName) .withContent('\n' + node.values .map(enumOption => { const name = enumOption.name.value; const enumValue = getValueFromConfig(name) ?? name; const comment = transformComment(enumOption.description?.value, 1); return comment + indent('| ' + wrapWithSingleQuotes(enumValue)); }) .concat(...withFutureAddedValue) .join('\n')).string; } if (outputType === 'native-numeric') { return new DeclarationBlock(declarationBlockConfig) .export() .withComment(node.description?.value) .withName(enumTypeName) .asKind('enum') .withBlock(node.values .map((enumOption, i) => { const valueFromConfig = getValueFromConfig(enumOption.name.value); const enumValue = valueFromConfig ?? i; const comment = transformComment(enumOption.description?.value, 1); const optionName = makeValidEnumIdentifier(convertName({ options: { typesPrefix: naming.typesPrefix, typesSuffix: naming.typesSuffix, useTypesPrefix: false, }, convert: () => naming.convert(enumOption, { transformUnderscore: true }), })); return comment + indent(optionName) + ` = ${enumValue}`; }) .concat(...withFutureAddedValue) .join(',\n')).string; } if (outputType === 'const') { const typeName = `export type ${enumTypeName} = typeof ${enumTypeName}[keyof typeof ${enumTypeName}];`; const enumAsConst = new DeclarationBlock({ ...declarationBlockConfig, blockTransformer: block => { return block + ' as const'; }, }) .export() .asKind('const') .withName(enumTypeName) .withComment(node.description?.value) .withBlock(node.values .map(enumOption => { const optionName = makeValidEnumIdentifier(convertName({ options: { typesPrefix: naming.typesPrefix, typesSuffix: naming.typesPrefix, }, convert: () => naming.convert(enumOption, { transformUnderscore: true, }), })); const comment = transformComment(enumOption.description?.value, 1); const name = enumOption.name.value; const enumValue = getValueFromConfig(name) ?? name; return comment + indent(`${optionName}: ${wrapWithSingleQuotes(enumValue)}`); }) .join(',\n')).string; return [enumAsConst, typeName].join('\n'); } return new DeclarationBlock(declarationBlockConfig) .export() .asKind(outputType === 'native-const' ? 'const enum' : 'enum') .withName(enumTypeName) .withComment(node.description?.value) .withBlock(buildEnumValuesBlock({ typeName: enumName, values: node.values, schema, naming, ignoreEnumValuesFromSchema, declarationBlockConfig, enumValues, })).string; }; export const buildEnumValuesBlock = ({ typeName, values, schema, naming, ignoreEnumValuesFromSchema, declarationBlockConfig, enumValues, }) => { const schemaEnumType = schema ? schema.getType(typeName) : undefined; return values .map(enumOption => { const onlyUnderscoresPattern = /^_+$/; const optionName = makeValidEnumIdentifier(convertName({ options: { useTypesPrefix: false, typesPrefix: naming.typesPrefix, typesSuffix: naming.typesSuffix, }, convert: () => naming.convert(enumOption, { // We can only strip out the underscores if the value contains other // characters. Otherwise we'll generate syntactically invalid code. transformUnderscore: !onlyUnderscoresPattern.test(enumOption.name.value), }), })); const comment = getNodeComment(enumOption); const schemaEnumValue = schemaEnumType && !ignoreEnumValuesFromSchema ? schemaEnumType.getValue(enumOption.name.value).value : undefined; let enumValue = typeof schemaEnumValue === 'undefined' ? enumOption.name.value : schemaEnumValue; if (typeof enumValues[typeName]?.mappedValues?.[enumValue] !== 'undefined') { enumValue = enumValues[typeName].mappedValues[enumValue]; } return (comment + indent(`${optionName}${declarationBlockConfig.enumNameValueSeparator} ${wrapWithSingleQuotes(enumValue, typeof schemaEnumValue !== 'undefined')}`)); }) .join(',\n'); }; const makeValidEnumIdentifier = (identifier) => { if (/^[0-9]/.exec(identifier)) { return wrapWithSingleQuotes(identifier, true); } return identifier; }; const convertName = ({ convert, options, }) => { const useTypesPrefix = typeof options.useTypesPrefix === 'boolean' ? options.useTypesPrefix : true; const useTypesSuffix = typeof options.useTypesSuffix === 'boolean' ? options.useTypesSuffix : true; let convertedName = ''; if (useTypesPrefix) { convertedName += options.typesPrefix; } convertedName += convert(); if (useTypesSuffix) { convertedName += options.typesSuffix; } return convertedName; };