UNPKG

@aws-amplify/appsync-modelgen-plugin

Version:
239 lines 12.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.AppSyncModelTypeScriptVisitor = void 0; const visitor_plugin_common_1 = require("@graphql-codegen/visitor-plugin-common"); const typescript_declaration_block_1 = require("../languages/typescript-declaration-block"); const appsync_visitor_1 = require("./appsync-visitor"); const change_case_1 = require("change-case"); class AppSyncModelTypeScriptVisitor extends appsync_visitor_1.AppSyncModelVisitor { constructor() { super(...arguments); this.SCALAR_TYPE_MAP = { String: 'string', Int: 'number', Float: 'number', Boolean: 'boolean', ID: 'string', }; this.IMPORT_STATEMENTS = [ 'import { ModelInit, MutableModel, PersistentModelConstructor } from "@aws-amplify/datastore";', 'import { initSchema } from "@aws-amplify/datastore";', '', 'import { schema } from "./schema";', ]; this.BASE_DATASTORE_IMPORT = new Set(['ModelInit', 'MutableModel']); this.TS_IGNORE_DATASTORE_IMPORT = new Set(['LazyLoading', 'LazyLoadingDisabled']); this.MODEL_META_FIELD_NAME = '__modelMeta__'; } generate() { const shouldUseModelNameFieldInHasManyAndBelongsTo = false; const shouldImputeKeyForUniDirectionalHasMany = true; const shouldUseFieldsInAssociatedWithInHasOne = true; this.processDirectives(shouldUseModelNameFieldInHasManyAndBelongsTo, shouldImputeKeyForUniDirectionalHasMany, shouldUseFieldsInAssociatedWithInHasOne); const imports = this.generateImports(); const enumDeclarations = Object.values(this.enumMap) .map(enumObj => this.generateEnumDeclarations(enumObj)) .join('\n\n'); const modelDeclarations = Object.values(this.modelMap) .map(typeObj => this.generateModelDeclaration(typeObj)) .join('\n\n'); const nonModelDeclarations = Object.values(this.nonModelMap) .map(typeObj => this.generateModelDeclaration(typeObj, true, false)) .join('\n\n'); const modelInitialization = this.generateModelInitialization([...Object.values(this.modelMap), ...Object.values(this.nonModelMap)]); const modelExports = this.generateExports(Object.values(this.modelMap)); return [imports, enumDeclarations, modelDeclarations, nonModelDeclarations, modelInitialization, modelExports].join('\n\n'); } generateImports() { return this.IMPORT_STATEMENTS.join('\n'); } generateEnumDeclarations(enumObj, exportEnum = false) { const enumDeclarations = new typescript_declaration_block_1.TypeScriptDeclarationBlock() .asKind('enum') .withName((0, change_case_1.pascalCase)(this.getEnumName(enumObj))) .withEnumValues(enumObj.values) .export(exportEnum); return enumDeclarations.string; } generateModelMetaData(modelObj) { const modelName = this.generateModelTypeDeclarationName(modelObj); const modelDeclarations = new typescript_declaration_block_1.TypeScriptDeclarationBlock() .asKind('type') .withName(`${modelName}MetaData`) .export(false); let readOnlyFieldNames = []; modelObj.fields.forEach((field) => { if (field.isReadOnly) { readOnlyFieldNames.push(`'${field.name}'`); } }); if (readOnlyFieldNames.length) { modelDeclarations.addProperty('readOnlyFields', readOnlyFieldNames.join(' | ')); return modelDeclarations.string; } return ''; } generateModelMetaDataType(modelObj) { let readOnlyFieldNames = []; modelObj.fields.forEach((field) => { if (field.isReadOnly) { readOnlyFieldNames.push(`'${field.name}'`); } }); let modelMetaFields = []; modelMetaFields.push(`identifier: ${this.constructIdentifier(modelObj)};`); if (readOnlyFieldNames.length) { modelMetaFields.push(`readOnlyFields: ${readOnlyFieldNames.join(' | ')};`); } const result = ['{', (0, visitor_plugin_common_1.indentMultiline)(modelMetaFields.join('\n')), '}']; return result.join('\n'); } constructIdentifier(modelObj) { const primaryKeyField = modelObj.fields.find(f => f.primaryKeyInfo); const { primaryKeyType, sortKeyFields } = primaryKeyField.primaryKeyInfo; switch (primaryKeyType) { case appsync_visitor_1.CodeGenPrimaryKeyType.ManagedId: this.BASE_DATASTORE_IMPORT.add('ManagedIdentifier'); return `ManagedIdentifier<${modelObj.name}, '${primaryKeyField.name}'>`; case appsync_visitor_1.CodeGenPrimaryKeyType.OptionallyManagedId: this.BASE_DATASTORE_IMPORT.add('OptionallyManagedIdentifier'); return `OptionallyManagedIdentifier<${modelObj.name}, '${primaryKeyField.name}'>`; case appsync_visitor_1.CodeGenPrimaryKeyType.CustomId: const identifierFields = [primaryKeyField.name, ...sortKeyFields.map(f => f.name)].filter(f => f); const identifierFieldsStr = identifierFields.length === 1 ? `'${identifierFields[0]}'` : `[${identifierFields.map(fieldStr => `'${fieldStr}'`).join(', ')}]`; if (identifierFields.length > 1) { this.BASE_DATASTORE_IMPORT.add('CompositeIdentifier'); return `CompositeIdentifier<${modelObj.name}, ${identifierFieldsStr}>`; } this.BASE_DATASTORE_IMPORT.add('CustomIdentifier'); return `CustomIdentifier<${modelObj.name}, ${identifierFieldsStr}>`; } } generateModelDeclaration(modelObj, isDeclaration = true, isModelType = true) { const modelName = this.generateModelTypeDeclarationName(modelObj); const eagerModelDeclaration = new typescript_declaration_block_1.TypeScriptDeclarationBlock().asKind('type').withName(`Eager${modelName}`); const lazyModelDeclaration = new typescript_declaration_block_1.TypeScriptDeclarationBlock().asKind('type').withName(`Lazy${modelName}`); let readOnlyFieldNames = []; let modelMetaDataFormatted; let modelMetaDataDeclaration = ''; if (isModelType && this.isCustomPKEnabled()) { this.BASE_DATASTORE_IMPORT.add(this.MODEL_META_FIELD_NAME); const modelMetaDataType = this.generateModelMetaDataType(modelObj); eagerModelDeclaration.addProperty(`[${this.MODEL_META_FIELD_NAME}]`, modelMetaDataType, undefined, 'DEFAULT', { readonly: true, optional: false, }); lazyModelDeclaration.addProperty(`[${this.MODEL_META_FIELD_NAME}]`, modelMetaDataType, undefined, 'DEFAULT', { readonly: true, optional: false, }); } modelObj.fields.forEach((field) => { const fieldName = this.getFieldName(field); eagerModelDeclaration.addProperty(fieldName, this.getNativeType(field), undefined, 'DEFAULT', { readonly: true, optional: field.isList ? field.isListNullable : field.isNullable, }); lazyModelDeclaration.addProperty(fieldName, this.getNativeType(field, { lazy: true }), undefined, 'DEFAULT', { readonly: true, optional: !this.isModelType(field) && (field.isList ? field.isListNullable : field.isNullable), }); if (field.isReadOnly) { readOnlyFieldNames.push(`'${field.name}'`); } }); if (isModelType && !this.isCustomPKEnabled()) { modelMetaDataFormatted = `, ${modelName}MetaData`; modelMetaDataDeclaration = readOnlyFieldNames.length > 0 ? modelMetaDataFormatted : ''; } const conditionalType = `export declare type ${modelName} = LazyLoading extends LazyLoadingDisabled ? Eager${modelName} : Lazy${modelName}`; const modelVariableBase = `export declare const ${modelName}: (new (init: ModelInit<${modelName}${modelMetaDataDeclaration}>) => ${modelName})`; const modelVariable = modelVariableBase + (Object.values(this.modelMap).includes(modelObj) ? ` & {\n copyOf(source: ${modelName}, mutator: (draft: MutableModel<${modelName}${modelMetaDataDeclaration}>) => MutableModel<${modelName}${modelMetaDataDeclaration}> | void): ${modelName};\n}` : ''); return [eagerModelDeclaration.string, lazyModelDeclaration.string, conditionalType, modelVariable].join('\n\n'); } generateModelInitialization(models, includeTypeInfo = true) { if (models.length === 0) { return ''; } const modelClasses = models .map(model => [this.generateModelImportName(model), this.generateModelImportAlias(model)]) .map(([importName, aliasName]) => { return importName === aliasName ? importName : `${importName}: ${aliasName}`; }); const initializationResult = ['const', '{', modelClasses.join(', '), '}', '=', 'initSchema(schema)']; if (includeTypeInfo) { const typeInfo = models .map(model => { return [this.generateModelImportName(model), this.generateModelTypeDeclarationName(model)]; }) .map(([importName, modelDeclarationName]) => `${importName}: PersistentModelConstructor<${modelDeclarationName}>;`); const typeInfoStr = ['{', (0, visitor_plugin_common_1.indentMultiline)(typeInfo.join('\n')), '}'].join('\n'); initializationResult.push('as', typeInfoStr); } return `${initializationResult.join(' ')};`; } generateExports(modelsOrEnum) { const exportStr = modelsOrEnum .map(model => { if (model.type === 'model') { const modelClassName = this.generateModelImportAlias(model); const exportClassName = this.getModelName(model); return modelClassName !== exportClassName ? `${modelClassName} as ${exportClassName}` : modelClassName; } return model.name; }) .join(',\n'); return ['export {', (0, visitor_plugin_common_1.indentMultiline)(exportStr), '};'].join('\n'); } generateModelTypeDeclarationName(model) { return `${this.getModelName(model)}Model`; } generateModelImportAlias(model) { return this.getModelName(model); } generateModelImportName(model) { return this.getModelName(model); } generateModelExportName(model) { return this.getModelName(model); } getListType(typeStr, field) { let type = typeStr; if (field.isNullable) { type = `(${type} | null)`; } return `${type}[]`; } getNativeType(field, options) { const typeName = field.type; const isNullable = field.isList ? field.isListNullable : field.isNullable; const nullableTypeUnion = isNullable ? ' | null' : ''; if (this.isModelType(field)) { const modelType = this.modelMap[typeName]; const typeNameStr = this.generateModelTypeDeclarationName(modelType); if (options === null || options === void 0 ? void 0 : options.lazy) { if (field.isList) { this.TS_IGNORE_DATASTORE_IMPORT.add('AsyncCollection'); } else { this.TS_IGNORE_DATASTORE_IMPORT.add('AsyncItem'); } return `${field.isList ? 'AsyncCollection' : 'AsyncItem'}<${typeNameStr}${!field.isList && isNullable ? ' | undefined' : ''}>`; } return (field.isList ? this.getListType(typeNameStr, field) : typeNameStr) + nullableTypeUnion; } let nativeType = super.getNativeType(field); if (this.isEnumType(field)) { const baseEnumType = `keyof typeof ${this.getEnumName(this.enumMap[typeName])}`; const enumType = field.isList ? `Array<${baseEnumType}>` : baseEnumType; nativeType = `${nativeType} | ${enumType}`; } nativeType = nativeType + nullableTypeUnion; return nativeType; } } exports.AppSyncModelTypeScriptVisitor = AppSyncModelTypeScriptVisitor; //# sourceMappingURL=appsync-typescript-visitor.js.map