@aws-amplify/appsync-modelgen-plugin
Version:
798 lines • 54.4 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AppSyncModelDartVisitor = void 0;
const appsync_visitor_1 = require("./appsync-visitor");
const dart_declaration_block_1 = require("../languages/dart-declaration-block");
const process_connections_1 = require("../utils/process-connections");
const visitor_plugin_common_1 = require("@graphql-codegen/visitor-plugin-common");
const process_auth_1 = require("../utils/process-auth");
const warn_1 = require("../utils/warn");
const dart_config_1 = require("../configs/dart-config");
const generateLicense_1 = require("../utils/generateLicense");
const scalars_1 = require("../scalars");
const change_case_1 = require("change-case");
class AppSyncModelDartVisitor extends appsync_visitor_1.AppSyncModelVisitor {
constructor(schema, rawConfig, additionalConfig, defaultScalars = scalars_1.DART_SCALAR_MAP) {
super(schema, rawConfig, additionalConfig, defaultScalars);
}
generate() {
const shouldUseModelNameFieldInHasManyAndBelongsTo = true;
const shouldImputeKeyForUniDirectionalHasMany = false;
this.processDirectives(shouldUseModelNameFieldInHasManyAndBelongsTo, shouldImputeKeyForUniDirectionalHasMany);
this.validateReservedKeywords();
if (this._parsedConfig.generate === appsync_visitor_1.CodeGenGenerateEnum.loader) {
return this.generateClassLoader();
}
else if (this.selectedTypeIsEnum()) {
return this.generateEnums();
}
else if (this.selectedTypeIsNonModel()) {
return this.generateNonModelClasses();
}
return this.generateModelClasses();
}
validateReservedKeywords() {
Object.entries({ ...this.models, ...this.nonModels }).forEach(([name, obj]) => {
if (dart_config_1.DART_RESERVED_KEYWORDS.includes(name)) {
throw new Error(`Type name '${name}' is a reserved word in dart. Please use a non-reserved name instead.`);
}
obj.fields.forEach(field => {
const fieldName = this.getFieldName(field);
if (dart_config_1.DART_RESERVED_KEYWORDS.includes(fieldName)) {
throw new Error(`Field name '${fieldName}' in type '${name}' is a reserved word in dart. Please use a non-reserved name instead.`);
}
});
});
Object.entries(this.enums).forEach(([name, enumVal]) => {
if (dart_config_1.DART_RESERVED_KEYWORDS.includes(name)) {
throw new Error(`Enum name '${name}' is a reserved word in dart. Please use a non-reserved name instead.`);
}
Object.values(enumVal.values).forEach(val => {
if (dart_config_1.DART_RESERVED_KEYWORDS.includes(val)) {
throw new Error(`Enum value '${val}' in enum '${name}' is a reserved word in dart. Please use a non-reserved name instead.`);
}
});
});
}
generateClassLoader() {
const result = [];
const modelNames = Object.keys(this.modelMap).sort();
const nonModelNames = Object.keys(this.nonModelMap).sort();
const exportClasses = [...modelNames, ...Object.keys(this.enumMap), ...Object.keys(this.nonModelMap)].sort();
const license = (0, generateLicense_1.generateLicense)();
result.push(license);
result.push(dart_config_1.CUSTOM_LINTS_MESSAGE);
result.push(dart_config_1.IGNORE_FOR_FILE);
const flutterDatastorePackage = dart_config_1.FLUTTER_AMPLIFY_CORE_IMPORT;
const packageImports = [...modelNames, ...nonModelNames];
const packageExports = [...exportClasses];
const classDeclarationBlock = new dart_declaration_block_1.DartDeclarationBlock()
.asKind('class')
.withName(dart_config_1.LOADER_CLASS_NAME)
.implements([`${dart_config_1.DART_AMPLIFY_CORE_TYPES.ModelProviderInterface}`])
.addClassMember('version', 'String', `"${this.computeVersion()}"`, undefined, ['override'])
.addClassMember('modelSchemas', `List<${dart_config_1.DART_AMPLIFY_CORE_TYPES.ModelSchema}>`, `[${modelNames.map(m => `${m}.schema`).join(', ')}]`, undefined, ['override'])
.addClassMember('customTypeSchemas', `List<${dart_config_1.DART_AMPLIFY_CORE_TYPES.ModelSchema}>`, `[${nonModelNames.map(nm => `${nm}.schema`).join(', ')}]`, undefined, ['override'])
.addClassMember('_instance', dart_config_1.LOADER_CLASS_NAME, `${dart_config_1.LOADER_CLASS_NAME}()`, { static: true, final: true })
.addClassMethod('get instance', dart_config_1.LOADER_CLASS_NAME, [], ' => _instance;', { isBlock: false, isGetter: true, static: true });
if (modelNames.length) {
const getModelTypeImplStr = [
'switch(modelName) {',
...modelNames.map(modelName => [(0, visitor_plugin_common_1.indent)(`case "${modelName}":`), (0, visitor_plugin_common_1.indent)(`return ${modelName}.classType;`, 2)].join('\n')),
(0, visitor_plugin_common_1.indent)('default:'),
(0, visitor_plugin_common_1.indent)('throw Exception("Failed to find model in model provider for model name: " + modelName);', 2),
'}',
].join('\n');
classDeclarationBlock.addClassMethod('getModelTypeByModelName', `${dart_config_1.DART_AMPLIFY_CORE_TYPES.ModelType}`, [{ type: 'String', name: 'modelName' }], getModelTypeImplStr);
}
const processedPackageImports = packageImports.map(p => `import '${p}.dart';`);
processedPackageImports.unshift(`import '${flutterDatastorePackage}.dart' as ${dart_config_1.AMPLIFY_CORE_PREFIX};`);
result.push(processedPackageImports.join('\n'));
result.push(packageExports.map(p => `export '${p}.dart';`).join('\n'));
result.push(classDeclarationBlock.string);
result.push(dart_config_1.MODEL_FILED_VALUE_CLASS);
return result.join('\n\n');
}
generateEnums() {
const result = [];
const license = (0, generateLicense_1.generateLicense)();
result.push(license);
result.push(dart_config_1.CUSTOM_LINTS_MESSAGE);
result.push(dart_config_1.IGNORE_FOR_FILE);
Object.entries(this.getSelectedEnums()).forEach(([name, enumVal]) => {
const body = Object.values(enumVal.values).join(',\n');
result.push([`enum ${(0, change_case_1.pascalCase)(name)} {`, (0, visitor_plugin_common_1.indentMultiline)(body), '}'].join('\n'));
});
return result.join('\n\n');
}
generateModelClasses() {
const result = [];
const license = (0, generateLicense_1.generateLicense)();
result.push(license);
result.push(dart_config_1.CUSTOM_LINTS_MESSAGE);
result.push(dart_config_1.IGNORE_FOR_FILE);
const packageImports = this.generatePackageHeader();
result.push(packageImports);
Object.entries(this.getSelectedModels()).forEach(([name, model]) => {
const modelDeclaration = this.generateModelClass(model);
const modelType = this.generateModelType(model);
result.push(modelDeclaration);
result.push(modelType);
if (this.isCustomPKEnabled()) {
const modelIdentifier = this.generateModelIdentifierClass(model);
result.push(modelIdentifier);
}
});
return result.join('\n\n');
}
generateNonModelClasses() {
const result = [];
const license = (0, generateLicense_1.generateLicense)();
result.push(license);
result.push(dart_config_1.CUSTOM_LINTS_MESSAGE);
result.push(dart_config_1.IGNORE_FOR_FILE);
const packageImports = this.generatePackageHeader();
result.push(packageImports);
Object.entries(this.getSelectedNonModels()).forEach(([name, model]) => {
const modelDeclaration = this.generateNonModelClass(model);
result.push(modelDeclaration);
});
return result.join('\n\n');
}
generatePackageHeader() {
let usingCollection = false;
Object.entries({ ...this.getSelectedModels(), ...this.getSelectedNonModels() }).forEach(([name, model]) => {
model.fields.forEach(f => {
if (f.isList) {
usingCollection = true;
}
});
});
const flutterDatastorePackage = dart_config_1.FLUTTER_AMPLIFY_CORE_IMPORT;
const packagesImports = [usingCollection ? dart_config_1.COLLECTION_PACKAGE : '', `${dart_config_1.LOADER_CLASS_NAME}.dart`]
.filter(f => f)
.map(pckg => `import '${pckg}';`);
packagesImports.push(`import '${flutterDatastorePackage}.dart' as ${dart_config_1.AMPLIFY_CORE_PREFIX};`);
return packagesImports.sort().join('\n') + '\n';
}
generateModelClass(model) {
const classDeclarationBlock = new dart_declaration_block_1.DartDeclarationBlock()
.asKind('class')
.withName(this.getModelName(model))
.extends([`${dart_config_1.DART_AMPLIFY_CORE_TYPES.Model}`])
.withComment(`This is an auto generated class representing the ${model.name} type in your schema.`);
classDeclarationBlock.addClassMember('classType', '', `const _${this.getModelName(model)}ModelType()`, { static: true, const: true });
model.fields.forEach(field => {
this.generateModelField(field, '', classDeclarationBlock);
});
classDeclarationBlock.addClassMethod('getInstanceType', '', [], ' => classType;', { isBlock: false }, ['override']);
this.generateGetters(model, classDeclarationBlock);
this.generateConstructor(model, classDeclarationBlock);
this.generateEqualsMethodAndOperator(model, classDeclarationBlock);
this.generateHashCodeMethod(model, classDeclarationBlock);
this.generateToStringMethod(model, classDeclarationBlock);
this.generateCopyWithMethod(model, classDeclarationBlock);
this.generateCopyWithModelFieldValuesMethod(model, classDeclarationBlock);
this.generateSerializationMethod(model, classDeclarationBlock);
this.generateModelSchema(model, classDeclarationBlock);
return classDeclarationBlock.string;
}
generateNonModelClass(model) {
const includeIdGetter = false;
const classDeclarationBlock = new dart_declaration_block_1.DartDeclarationBlock()
.asKind('class')
.withName(this.getModelName(model))
.withComment(`This is an auto generated class representing the ${model.name} type in your schema.`);
model.fields.forEach(field => {
this.generateModelField(field, '', classDeclarationBlock);
});
this.generateGetters(model, classDeclarationBlock, includeIdGetter);
this.generateConstructor(model, classDeclarationBlock);
this.generateEqualsMethodAndOperator(model, classDeclarationBlock);
this.generateHashCodeMethod(model, classDeclarationBlock);
this.generateToStringMethod(model, classDeclarationBlock);
this.generateCopyWithMethod(model, classDeclarationBlock);
this.generateCopyWithModelFieldValuesMethod(model, classDeclarationBlock);
this.generateSerializationMethod(model, classDeclarationBlock);
this.generateNonModelSchema(model, classDeclarationBlock);
return classDeclarationBlock.string;
}
generateModelType(model) {
const modelName = this.getModelName(model);
const classDeclarationBlock = new dart_declaration_block_1.DartDeclarationBlock()
.asKind('class')
.withName(`_${modelName}ModelType`)
.extends([`${dart_config_1.DART_AMPLIFY_CORE_TYPES.ModelType}<${modelName}>`]);
classDeclarationBlock.addClassMethod(`_${modelName}ModelType`, '', [], ';', { const: true, isBlock: false });
classDeclarationBlock.addClassMethod('fromJson', modelName, [{ name: 'jsonData', type: 'Map<String, dynamic>' }], `return ${modelName}.fromJson(jsonData);`, undefined, ['override']);
classDeclarationBlock.addClassMethod('modelName', 'String', [], `return '${modelName}';`, undefined, ['override']);
return classDeclarationBlock.string;
}
generateModelIdentifierClass(model) {
const identifierFields = this.getModelIdentifierFields(model);
const modelName = this.getModelName(model);
const classDeclarationBlock = new dart_declaration_block_1.DartDeclarationBlock()
.asKind('class')
.withName(`${modelName}ModelIdentifier`)
.implements([`${dart_config_1.DART_AMPLIFY_CORE_TYPES.ModelIdentifier}<${modelName}>`])
.withComment(['This is an auto generated class representing the model identifier', `of [${modelName}] in your schema.`].join('\n'));
identifierFields.forEach(field => {
classDeclarationBlock.addClassMember(field.name, this.getNativeType(field), '', { final: true });
});
const constructorArgs = `{\n${(0, visitor_plugin_common_1.indentMultiline)(identifierFields.map(field => `required this.${field.name}`).join(',\n'))}}`;
classDeclarationBlock.addClassMethod(`${modelName}ModelIdentifier`, '', [{ name: constructorArgs }], ';', { const: true, isBlock: false }, undefined, [
`Create an instance of ${modelName}ModelIdentifier using [${identifierFields[0].name}] the primary key.`,
identifierFields.length > 1
? `And ${identifierFields
.slice(1)
.map(field => `[${field.name}]`)
.join(', ')} the sort key${identifierFields.length == 2 ? '' : 's'}.`
: undefined,
]
.filter(comment => comment)
.join('\n'));
classDeclarationBlock.addClassMethod('serializeAsMap', 'Map<String, dynamic>', [], [' => (<String, dynamic>{', (0, visitor_plugin_common_1.indentMultiline)(identifierFields.map(field => `'${field.name}': ${field.name}`).join(',\n')), '});'].join('\n'), { isBlock: false }, ['override']);
classDeclarationBlock.addClassMethod('serializeAsList', 'List<Map<String, dynamic>>', [], [
' => serializeAsMap()',
(0, visitor_plugin_common_1.indent)('.entries'),
(0, visitor_plugin_common_1.indent)('.map((entry) => (<String, dynamic>{ entry.key: entry.value }))'),
(0, visitor_plugin_common_1.indent)('.toList();'),
].join('\n'), { isBlock: false }, ['override']);
classDeclarationBlock.addClassMethod('serializeAsString', 'String', undefined, " => serializeAsMap().values.join('#');", {
isBlock: false,
}, ['override']);
classDeclarationBlock.addClassMethod('toString', 'String', undefined, ` => '${modelName}ModelIdentifier(${identifierFields.map(field => `${field.name}: $${field.name}`).join(', ')})';`, { isBlock: false }, ['override']);
const equalOperatorImpl = [
'if (identical(this, other)) {',
(0, visitor_plugin_common_1.indent)('return true;'),
'}\n',
`return other is ${modelName}ModelIdentifier &&`,
(0, visitor_plugin_common_1.indentMultiline)(`${identifierFields.map(field => `${field.name} == other.${field.name}`).join(' &&\n')};`),
].join('\n');
classDeclarationBlock.addClassMethod('operator ==', 'bool', [{ name: 'Object other' }], equalOperatorImpl, undefined, ['override']);
classDeclarationBlock.addClassMethod('get hashCode', 'int', undefined, ` =>\n${(0, visitor_plugin_common_1.indentMultiline)(identifierFields.map(field => `${field.name}.hashCode`).join(' ^\n'))};`, { isBlock: false, isGetter: true }, ['override']);
return classDeclarationBlock.string;
}
generateModelField(field, value, classDeclarationBlock) {
const fieldType = this.getNativeType(field);
const fieldName = this.getFieldName(field);
if (fieldName !== 'id') {
classDeclarationBlock.addClassMember(`_${fieldName}`, `${fieldType}?`, value, { final: true });
}
else {
classDeclarationBlock.addClassMember(fieldName, fieldType, value, { final: true });
}
}
generateGetters(model, declarationBlock, includeIdGetter = true) {
if (includeIdGetter) {
if (this.isCustomPKEnabled()) {
const identifierFields = this.getModelIdentifierFields(model);
const isCustomPK = identifierFields[0].name !== 'id';
const getIdImpl = isCustomPK ? ' => modelIdentifier.serializeAsString();' : ' => id;';
declarationBlock.addClassMethod('getId', 'String', [], getIdImpl, { isBlock: false }, [
"Deprecated('[getId] is being deprecated in favor of custom primary key feature. Use getter [modelIdentifier] to get model identifier.')",
'override',
]);
}
else {
declarationBlock.addClassMethod('getId', 'String', [], 'return id;', {}, ['override']);
}
}
let forceCastException = `throw ${dart_config_1.DART_AMPLIFY_CORE_TYPES.AmplifyCodeGenModelException}(
${dart_config_1.DART_AMPLIFY_CORE_TYPES.AmplifyExceptionMessages}.codeGenRequiredFieldForceCastExceptionMessage,
recoverySuggestion:
${dart_config_1.DART_AMPLIFY_CORE_TYPES.AmplifyExceptionMessages}.codeGenRequiredFieldForceCastRecoverySuggestion,
underlyingException: e.toString()
);`;
if (includeIdGetter && this.isCustomPKEnabled()) {
this.generateModelIdentifierGetter(model, declarationBlock, forceCastException);
}
model.fields.forEach(field => {
const fieldName = this.getFieldName(field);
const fieldType = this.getNativeType(field);
const returnType = this.isFieldRequired(field) ? fieldType : `${fieldType}?`;
const getterImpl = this.isFieldRequired(field)
? [`try {`, (0, visitor_plugin_common_1.indent)(`return _${fieldName}!;`), '} catch(e) {', (0, visitor_plugin_common_1.indent)(forceCastException), '}'].join('\n')
: `return _${fieldName};`;
if (fieldName !== 'id') {
declarationBlock.addClassMethod(`get ${fieldName}`, returnType, undefined, getterImpl, { isGetter: true, isBlock: true });
}
});
}
generateModelIdentifierGetter(model, declarationBlock, forceCastException) {
const identifierFields = this.getModelIdentifierFields(model);
const modelName = this.getModelName(model);
const isSingleManagedIDField = identifierFields.length === 1 && identifierFields[0].name === 'id';
const getterImpl = [
isSingleManagedIDField ? undefined : 'try {',
(0, visitor_plugin_common_1.indent)(`return ${modelName}ModelIdentifier(`),
(0, visitor_plugin_common_1.indentMultiline)(identifierFields
.map(field => {
const isManagedIdField = field.name === 'id';
return (0, visitor_plugin_common_1.indent)(`${field.name}: ${isManagedIdField ? '' : '_'}${field.name}${isManagedIdField ? '' : '!'}`);
})
.join(',\n')),
(0, visitor_plugin_common_1.indent)(');'),
isSingleManagedIDField ? undefined : '} catch(e) {',
isSingleManagedIDField ? undefined : (0, visitor_plugin_common_1.indent)(forceCastException),
isSingleManagedIDField ? undefined : '}',
]
.filter(line => line)
.join('\n');
declarationBlock.addClassMethod(`get modelIdentifier`, `${modelName}ModelIdentifier`, undefined, getterImpl, {
isGetter: true,
isBlock: true,
});
}
generateConstructor(model, declarationBlock) {
const args = `{${model.fields
.map(f => `${this.isFieldRequired(f) ? 'required ' : ''}${this.getFieldName(f) === 'id' ? 'this.' : ''}${this.getFieldName(f)}`)
.join(', ')}}`;
const internalFields = model.fields.filter(f => this.getFieldName(f) !== 'id');
const internalImpl = internalFields.length
? `: ${internalFields.map(f => `_${this.getFieldName(f)} = ${this.getFieldName(f)}`).join(', ')};`
: ';';
declarationBlock.addClassMethod(`${this.getModelName(model)}._internal`, '', [{ name: args }], internalImpl, {
const: true,
isBlock: false,
});
const writableFields = this.getWritableFields(model);
const returnParamStr = writableFields
.map(field => {
const fieldName = this.getFieldName(field);
if (fieldName === 'id') {
return `id: id == null ? ${dart_config_1.DART_AMPLIFY_CORE_TYPES.UUID}.getUUID() : id`;
}
else if (field.isList) {
return `${fieldName}: ${fieldName} != null ? ${this.getNativeType(field)}.unmodifiable(${fieldName}) : ${fieldName}`;
}
else {
return `${fieldName}: ${fieldName}`;
}
})
.join(',\n');
const factoryImpl = [`return ${this.getModelName(model)}._internal(`, (0, visitor_plugin_common_1.indentMultiline)(`${returnParamStr});`)].join('\n');
const factoryParam = `{${writableFields
.map(f => {
if (this.getFieldName(f) === 'id' || !this.isFieldRequired(f)) {
return `${this.getNativeType(f)}? ${this.getFieldName(f)}`;
}
return `required ${this.getNativeType(f)} ${this.getFieldName(f)}`;
})
.join(', ')}}`;
declarationBlock.addClassMethod(this.getModelName(model), 'factory', [{ name: factoryParam }], factoryImpl);
}
generateEqualsMethodAndOperator(model, declarationBlock) {
declarationBlock.addClassMethod('equals', 'bool', [{ name: 'other', type: 'Object' }], 'return this == other;');
const equalImpl = [
'if (identical(other, this)) return true;',
`return other is ${this.getModelName(model)} &&`,
(0, visitor_plugin_common_1.indentMultiline)(`${this.getWritableFields(model)
.map(f => {
const fieldName = `${f.name !== 'id' ? '_' : ''}${this.getFieldName(f)}`;
return f.isList ? `DeepCollectionEquality().equals(${fieldName}, other.${fieldName})` : `${fieldName} == other.${fieldName}`;
})
.join(' &&\n')};`),
].join('\n');
declarationBlock.addClassMethod('operator ==', 'bool', [{ name: 'other', type: 'Object' }], equalImpl, undefined, ['override']);
}
generateHashCodeMethod(model, declarationBlock) {
declarationBlock.addClassMethod(`get hashCode`, `int`, undefined, ' => toString().hashCode;', { isGetter: true, isBlock: false }, [
'override',
]);
}
generateToStringMethod(model, declarationBlock) {
const fields = this.getNonConnectedField(model);
declarationBlock.addClassMethod('toString', 'String', [], [
'var buffer = new StringBuffer();',
'',
`buffer.write("${this.getModelName(model)} {");`,
...fields.map((field, index) => {
const fieldDelimiter = ', ';
const varName = this.getFieldName(field);
const fieldName = `${field.name !== 'id' ? '_' : ''}${this.getFieldName(field)}`;
let toStringVal = '';
if (this.isEnumType(field)) {
if (field.isList) {
toStringVal = `(${fieldName} != null ? ${fieldName}!.map((e) => ${dart_config_1.DART_AMPLIFY_CORE_TYPES.enumToString}(e)).toString() : "null")`;
}
else {
toStringVal = `(${fieldName} != null ? ${dart_config_1.DART_AMPLIFY_CORE_TYPES.enumToString}(${fieldName})! : "null")`;
}
}
else {
const fieldNativeType = this.getNativeType(field);
switch (fieldNativeType) {
case 'String':
toStringVal = `"$${fieldName}"`;
break;
case this.scalars['AWSDate']:
case this.scalars['AWSTime']:
case this.scalars['AWSDateTime']:
toStringVal = `(${fieldName} != null ? ${fieldName}!.format() : "null")`;
break;
default:
toStringVal = `(${fieldName} != null ? ${fieldName}!.toString() : "null")`;
}
}
if (index !== fields.length - 1) {
return `buffer.write("${varName}=" + ${toStringVal} + "${fieldDelimiter}");`;
}
return `buffer.write("${varName}=" + ${toStringVal});`;
}),
`buffer.write("}");`,
'',
'return buffer.toString();',
].join('\n'), undefined, ['override']);
}
generateCopyWithMethod(model, declarationBlock) {
const writableFields = this.getWritableFields(model, this.isCustomPKEnabled());
const copyParam = `{${writableFields.map(f => `${this.getNativeType(f)}? ${this.getFieldName(f)}`).join(', ')}}`;
declarationBlock.addClassMethod('copyWith', this.getModelName(model), writableFields.length ? [{ name: copyParam }] : undefined, [
`return ${this.getModelName(model)}${this.config.isTimestampFieldsAdded ? '._internal' : ''}(`,
(0, visitor_plugin_common_1.indentMultiline)(`${this.getWritableFields(model)
.map(field => {
const fieldName = this.getFieldName(field);
return `${fieldName}: ${writableFields.findIndex(field => field.name === fieldName) > -1 ? `${fieldName} ?? this.` : ''}${fieldName}`;
})
.join(',\n')});`),
].join('\n'));
}
generateCopyWithModelFieldValuesMethod(model, declarationBlock) {
const writableFields = this.getWritableFields(model, this.isCustomPKEnabled());
const copyParameters = writableFields.map(field => `ModelFieldValue<${this.getNativeType(field)}${field.isNullable ? '?' : ''}>? ${this.getFieldName(field)}`);
const copyParameterStr = `{\n${(0, visitor_plugin_common_1.indentMultiline)(copyParameters.join(',\n'))}\n}`;
declarationBlock.addClassMethod('copyWithModelFieldValues', this.getModelName(model), writableFields.length ? [{ name: copyParameterStr }] : undefined, [
`return ${this.getModelName(model)}${this.config.isTimestampFieldsAdded ? '._internal' : ''}(`,
(0, visitor_plugin_common_1.indentMultiline)(`${this.getWritableFields(model, false)
.map(field => {
const fieldName = this.getFieldName(field);
return `${fieldName}: ${writableFields.findIndex(field => field.name === fieldName) > -1
? `${fieldName} == null ? this.${fieldName} : ${fieldName}.value`
: `${fieldName}`}`;
})
.join(',\n')}`),
');',
].join('\n'));
}
generateSerializationMethod(model, declarationBlock) {
const serializationImpl = `\n: ${(0, visitor_plugin_common_1.indentMultiline)(model.fields
.map(field => {
const varName = this.getFieldName(field);
const fieldName = `${field.name !== 'id' ? '_' : ''}${this.getFieldName(field)}`;
if (this.isModelType(field)) {
if (field.isList) {
return [
`${fieldName} = json['${varName}'] is Map`,
(0, visitor_plugin_common_1.indent)(`? (json['${varName}']['items'] is List`),
(0, visitor_plugin_common_1.indent)(`? (json['${varName}']['items'] as List)`, 2),
(0, visitor_plugin_common_1.indent)(`.where((e) => e != null)`, 4),
(0, visitor_plugin_common_1.indent)(`.map((e) => ${this.getNativeType({ ...field, isList: false })}.fromJson(new Map<String, dynamic>.from(e)))`, 4),
(0, visitor_plugin_common_1.indent)(`.toList()`, 4),
(0, visitor_plugin_common_1.indent)(`: null)`, 2),
(0, visitor_plugin_common_1.indent)(`: (json['${varName}'] is List`),
(0, visitor_plugin_common_1.indent)(`? (json['${varName}'] as List)`, 2),
(0, visitor_plugin_common_1.indent)(`.where((e) => e?['serializedData'] != null)`, 4),
(0, visitor_plugin_common_1.indent)(`.map((e) => ${this.getNativeType({ ...field, isList: false })}.fromJson(new Map<String, dynamic>.from(e?['serializedData'])))`, 4),
(0, visitor_plugin_common_1.indent)(`.toList()`, 4),
(0, visitor_plugin_common_1.indent)(`: null)`, 2),
]
.filter(e => e !== undefined)
.join('\n');
}
return [
`${fieldName} = json['${varName}'] != null`,
(0, visitor_plugin_common_1.indent)(`? json['${varName}']['serializedData'] != null`),
(0, visitor_plugin_common_1.indent)(`? ${this.getNativeType(field)}.fromJson(new Map<String, dynamic>.from(json['${varName}']['serializedData']))`, 2),
(0, visitor_plugin_common_1.indent)(`: ${this.getNativeType(field)}.fromJson(new Map<String, dynamic>.from(json['${varName}']))`, 2),
(0, visitor_plugin_common_1.indent)(`: null`),
].join('\n');
}
if (this.isEnumType(field)) {
if (field.isList) {
return [
`${fieldName} = json['${varName}'] is List`,
(0, visitor_plugin_common_1.indent)(`? (json['${varName}'] as List)`),
(0, visitor_plugin_common_1.indent)(`.map((e) => ${dart_config_1.DART_AMPLIFY_CORE_TYPES.enumFromString}<${field.type}>(e, ${field.type}.values)!)`, 2),
(0, visitor_plugin_common_1.indent)(`.toList()`, 2),
(0, visitor_plugin_common_1.indent)(`: null`),
].join('\n');
}
return `${fieldName} = ${dart_config_1.DART_AMPLIFY_CORE_TYPES.enumFromString}<${field.type}>(json['${varName}'], ${field.type}.values)`;
}
if (this.isNonModelType(field)) {
if (field.isList) {
return [
`${fieldName} = json['${varName}'] is List`,
(0, visitor_plugin_common_1.indent)(`? (json['${varName}'] as List)`),
(0, visitor_plugin_common_1.indent)(`.where((e) => e != null)`, 2),
(0, visitor_plugin_common_1.indent)(`.map((e) => ${this.getNativeType({ ...field, isList: false })}.fromJson(new Map<String, dynamic>.from(${this.isNonModelType(field) ? "e['serializedData'] ?? e" : 'e'})))`, 2),
(0, visitor_plugin_common_1.indent)(`.toList()`, 2),
(0, visitor_plugin_common_1.indent)(`: null`),
]
.filter(e => e !== undefined)
.join('\n');
}
return [
`${fieldName} = json['${varName}'] != null`,
(0, visitor_plugin_common_1.indent)(`? json['${varName}']['serializedData'] != null`, 2),
(0, visitor_plugin_common_1.indent)(`? ${this.getNativeType(field)}.fromJson(new Map<String, dynamic>.from(json['${varName}']['serializedData']))`, 4),
(0, visitor_plugin_common_1.indent)(`: ${this.getNativeType(field)}.fromJson(new Map<String, dynamic>.from(json['${varName}']))`, 4),
(0, visitor_plugin_common_1.indent)(`: null`),
].join('\n');
}
const fieldNativeType = this.getNativeType({ ...field, isList: false });
switch (fieldNativeType) {
case this.scalars['AWSDate']:
case this.scalars['AWSTime']:
case this.scalars['AWSDateTime']:
return field.isList
? `${fieldName} = (json['${varName}'] as ${this.getNullableTypeStr('List')})?.map((e) => ${fieldNativeType}.fromString(e)).toList()`
: `${fieldName} = json['${varName}'] != null ? ${fieldNativeType}.fromString(json['${varName}']) : null`;
case this.scalars['AWSTimestamp']:
return field.isList
? `${fieldName} = (json['${varName}'] as ${this.getNullableTypeStr('List')})?.map((e) => ${fieldNativeType}.fromSeconds(e)).toList()`
: `${fieldName} = json['${varName}'] != null ? ${fieldNativeType}.fromSeconds(json['${varName}']) : null`;
case this.scalars['Int']:
return field.isList
? `${fieldName} = (json['${varName}'] as ${this.getNullableTypeStr('List')})?.map((e) => (e as num).toInt()).toList()`
: `${fieldName} = (json['${varName}'] as ${this.getNullableTypeStr('num')})?.toInt()`;
case this.scalars['Float']:
return field.isList
? `${fieldName} = (json['${varName}'] as ${this.getNullableTypeStr('List')})?.map((e) => (e as num).toDouble()).toList()`
: `${fieldName} = (json['${varName}'] as ${this.getNullableTypeStr('num')})?.toDouble()`;
default:
return field.isList
? `${fieldName} = json['${varName}']?.cast<${this.getNativeType({ ...field, isList: false })}>()`
: `${fieldName} = json['${varName}']`;
}
})
.join(',\n')).trim()};`;
declarationBlock.addClassMethod(`${this.getModelName(model)}.fromJson`, ``, [{ name: 'json', type: 'Map<String, dynamic>' }], (0, visitor_plugin_common_1.indentMultiline)(serializationImpl), { isBlock: false });
const toJsonFields = model.fields
.map(field => {
const varName = this.getFieldName(field);
const fieldName = `${field.name !== 'id' ? '_' : ''}${this.getFieldName(field)}`;
if (this.isModelType(field) || this.isNonModelType(field)) {
if (field.isList) {
const modelName = this.getNativeType({ ...field, isList: false });
return `'${varName}': ${fieldName}?.map((${modelName}? e) => e?.toJson()).toList()`;
}
return `'${varName}': ${fieldName}?.toJson()`;
}
if (this.isEnumType(field)) {
if (field.isList) {
return `'${varName}': ${fieldName}?.map((e) => ${dart_config_1.DART_AMPLIFY_CORE_TYPES.enumToString}(e)).toList()`;
}
return `'${varName}': ${dart_config_1.DART_AMPLIFY_CORE_TYPES.enumToString}(${fieldName})`;
}
const fieldNativeType = this.getNativeType({ ...field, isList: false });
switch (fieldNativeType) {
case this.scalars['AWSDate']:
case this.scalars['AWSTime']:
case this.scalars['AWSDateTime']:
return field.isList ? `'${varName}': ${fieldName}?.map((e) => e.format()).toList()` : `'${varName}': ${fieldName}?.format()`;
case this.scalars['AWSTimestamp']:
return field.isList
? `'${varName}': ${fieldName}?.map((e) => e.toSeconds()).toList()`
: `'${varName}': ${fieldName}?.toSeconds()`;
default:
return `'${varName}': ${fieldName}`;
}
})
.join(', ');
const deserializationImpl = [' => {', (0, visitor_plugin_common_1.indentMultiline)(toJsonFields), '};'].join('\n');
declarationBlock.addClassMethod('toJson', 'Map<String, dynamic>', [], deserializationImpl, { isBlock: false });
const toMapFields = model.fields
.map(field => {
const varName = this.getFieldName(field);
const fieldName = `${field.name !== 'id' ? '_' : ''}${this.getFieldName(field)}`;
return `'${varName}': ${fieldName}`;
})
.join(',\n');
const toMapImpl = [' => {', (0, visitor_plugin_common_1.indentMultiline)(toMapFields), '};'].join('\n');
declarationBlock.addClassMethod('toMap', 'Map<String, Object?>', [], toMapImpl, { isBlock: false });
}
generateModelSchema(model, classDeclarationBlock) {
const modelName = model.name;
const schemaDeclarationBlock = new dart_declaration_block_1.DartDeclarationBlock();
if (this.isCustomPKEnabled()) {
schemaDeclarationBlock.addClassMember('MODEL_IDENTIFIER', `${dart_config_1.DART_AMPLIFY_CORE_TYPES.QueryModelIdentifier}<${modelName}ModelIdentifier>`, `${dart_config_1.DART_AMPLIFY_CORE_TYPES.QueryModelIdentifier}<${modelName}ModelIdentifier>()`, { static: true, final: true });
}
this.getWritableFields(model).forEach(field => {
this.generateQueryField(model, field, schemaDeclarationBlock);
});
this.generateSchemaField(model, schemaDeclarationBlock);
classDeclarationBlock.addBlock(schemaDeclarationBlock);
}
generateNonModelSchema(model, classDeclarationBlock) {
const isNonModel = true;
const schemaDeclarationBlock = new dart_declaration_block_1.DartDeclarationBlock();
this.generateSchemaField(model, schemaDeclarationBlock, isNonModel);
classDeclarationBlock.addBlock(schemaDeclarationBlock);
}
generateQueryField(model, field, declarationBlock) {
const fieldName = this.getFieldName(field);
const queryFieldName = this.getQueryFieldName(field);
let value = `${dart_config_1.DART_AMPLIFY_CORE_TYPES.QueryField}(fieldName: "${fieldName}")`;
if (this.isModelType(field)) {
const modelName = this.getNativeType({ ...field, isList: false });
value = [
`${dart_config_1.DART_AMPLIFY_CORE_TYPES.QueryField}(`,
(0, visitor_plugin_common_1.indent)(`fieldName: "${fieldName}",`),
(0, visitor_plugin_common_1.indent)(`fieldType: ${dart_config_1.DART_AMPLIFY_CORE_TYPES.ModelFieldType}(${dart_config_1.DART_AMPLIFY_CORE_TYPES.ModelFieldTypeEnum}.model, ofModelName: '${modelName}'))`),
].join('\n');
}
declarationBlock.addClassMember(queryFieldName, `${dart_config_1.DART_AMPLIFY_CORE_TYPES.QueryField}`, value, {
static: true,
final: true,
inferType: true,
});
}
getQueryFieldName(field) {
return this.getFieldName(field).toUpperCase();
}
generateSchemaField(model, declarationBlock, isNonModel = false) {
const schema = [
`${dart_config_1.DART_AMPLIFY_CORE_TYPES.Model}.defineSchema(define: (${dart_config_1.DART_AMPLIFY_CORE_TYPES.ModelSchemaDefinition} modelSchemaDefinition) {`,
(0, visitor_plugin_common_1.indentMultiline)([
`modelSchemaDefinition.name = "${this.getModelName(model)}";\nmodelSchemaDefinition.pluralName = "${this.pluralizeModelName(model)}";`,
this.generateAuthRules(model),
this.generateIndexes(model),
isNonModel ? this.generateNonModelAddFields(model) : this.generateAddFields(model),
]
.filter(f => f)
.join('\n\n')),
'})',
].join('\n');
declarationBlock.addClassMember('schema', '', schema, { static: true, var: true, inferType: true });
}
generateAuthRules(model) {
const authDirectives = model.directives.filter(d => d.name === 'auth');
if (authDirectives.length) {
const rules = [];
authDirectives.forEach(directive => {
var _a;
(_a = directive.arguments) === null || _a === void 0 ? void 0 : _a.rules.forEach(rule => {
var _a;
const authRule = [];
const authStrategy = `authStrategy: ${dart_config_1.DART_AMPLIFY_CORE_TYPES.AuthStrategy}.${rule.allow.toUpperCase()}`;
switch (rule.allow) {
case process_auth_1.AuthStrategy.owner:
authRule.push(authStrategy);
authRule.push(`ownerField: "${rule.ownerField}"`);
authRule.push(`identityClaim: "${rule.identityClaim}"`);
break;
case process_auth_1.AuthStrategy.private:
case process_auth_1.AuthStrategy.public:
authRule.push(authStrategy);
break;
case process_auth_1.AuthStrategy.groups:
authRule.push(authStrategy);
authRule.push(`groupClaim: "${rule.groupClaim}"`);
if (rule.groups) {
authRule.push(`groups: [ ${(_a = rule.groups) === null || _a === void 0 ? void 0 : _a.map(group => `"${group}"`).join(', ')} ]`);
}
else {
authRule.push(`groupsField: "${rule.groupField}"`);
}
break;
default:
(0, warn_1.printWarning)(`Model has auth with authStrategy ${rule.allow} of which is not yet supported`);
return '';
}
if (rule.provider) {
authRule.push(`provider: ${dart_config_1.DART_AMPLIFY_CORE_TYPES.AuthRuleProvider}.${rule.provider.toUpperCase()}`);
}
authRule.push([
'operations: const [',
(0, visitor_plugin_common_1.indentMultiline)(rule.operations.map(op => `${dart_config_1.DART_AMPLIFY_CORE_TYPES.ModelOperation}.${op.toUpperCase()}`).join(',\n')),
']',
].join('\n'));
rules.push(`${dart_config_1.DART_AMPLIFY_CORE_TYPES.AuthRule}(\n${(0, visitor_plugin_common_1.indentMultiline)(authRule.join(',\n'))})`);
});
});
if (rules.length) {
return ['modelSchemaDefinition.authRules = [', (0, visitor_plugin_common_1.indentMultiline)(rules.join(',\n')), '];'].join('\n');
}
}
return '';
}
generateIndexes(model) {
const indexes = model.directives
.filter(directive => directive.name === 'key')
.map(directive => {
const name = directive.arguments.name ? `"${directive.arguments.name}"` : 'null';
const fields = directive.arguments.fields.map((field) => `"${field}"`).join(', ');
return `${dart_config_1.DART_AMPLIFY_CORE_TYPES.ModelIndex}(fields: const [${fields}], name: ${name})`;
});
if (indexes.length) {
return ['modelSchemaDefinition.indexes = [', (0, visitor_plugin_common_1.indentMultiline)(indexes.join(',\n')), '];'].join('\n');
}
return '';
}
generateAddFields(model) {
if (model.fields.length) {
const fieldsToAdd = [];
model.fields.forEach(field => {
const fieldName = this.getFieldName(field);
const modelName = this.getModelName(model);
const queryFieldName = this.getQueryFieldName(field);
let fieldParam = '';
if (fieldName === 'id') {
fieldsToAdd.push(`${dart_config_1.DART_AMPLIFY_CORE_TYPES.ModelFieldDefinition}.id()`);
}
else if (field.connectionInfo) {
const connectedModelName = this.getNativeType({ ...field, isList: false });
switch (field.connectionInfo.kind) {
case process_connections_1.CodeGenConnectionType.HAS_ONE: {
let associatedString = `associatedKey: ${connectedModelName}.${this.getQueryFieldName(field.connectionInfo.associatedWith)}`;
if (field.connectionInfo.associatedWithNativeReferences) {
associatedString = `associatedKey: ${connectedModelName}.${this.getQueryFieldName(field.connectionInfo.associatedWithNativeReferences)}`;
}
fieldParam = [
`key: ${modelName}.${queryFieldName}`,
`isRequired: ${!field.isNullable}`,
`ofModelName: '${connectedModelName}'`,
associatedString,
].join(',\n');
fieldsToAdd.push([`${dart_config_1.DART_AMPLIFY_CORE_TYPES.ModelFieldDefinition}.hasOne(`, (0, visitor_plugin_common_1.indentMultiline)(fieldParam), ')'].join('\n'));
break;
}
case process_connections_1.CodeGenConnectionType.HAS_MANY: {
let associatedString = `associatedKey: ${connectedModelName}.${this.getQueryFieldName(field.connectionInfo.associatedWith)}`;
if (field.connectionInfo.associatedWithNativeReferences) {
associatedString = `associatedKey: ${connectedModelName}.${this.getQueryFieldName(field.connectionInfo.associatedWithNativeReferences)}`;
}
fieldParam = [
`key: ${modelName}.${queryFieldName}`,
`isRequired: ${!field.isNullable}`,
`ofModelName: '${connectedModelName}'`,
associatedString,
].join(',\n');
fieldsToAdd.push([`${dart_config_1.DART_AMPLIFY_CORE_TYPES.ModelFieldDefinition}.hasMany(`, (0, visitor_plugin_common_1.indentMultiline)(fieldParam), ')'].join('\n'));
break;
}
case process_connections_1.CodeGenConnectionType.BELONGS_TO:
fieldParam = [
`key: ${modelName}.${queryFieldName}`,
`isRequired: ${!field.isNullable}`,
this.isCustomPKEnabled()
? `targetNames: [${field.connectionInfo.targetNames.map(target => `'${target}'`).join(', ')}]`
: `targetName: '${field.connectionInfo.targetName}'`,
`ofModelName: '${connectedModelName}'`,
].join(',\n');
fieldsToAdd.push([`${dart_config_1.DART_AMPLIFY_CORE_TYPES.ModelFieldDefinition}.belongsTo(`, (0, visitor_plugin_common_1.indentMultiline)(fieldParam), ')'].join('\n'));
break;
}
}
else {
const ofType = this.getOfType(field);
let ofTypeStr;
if (field.isList) {
if (ofType === '.embedded') {
ofTypeStr = `ofType: ${dart_config_1.DART_AMPLIFY_CORE_TYPES.ModelFieldType}(${dart_config_1.DART_AMPLIFY_CORE_TYPES.ModelFieldTypeEnum}.embeddedCollection, ofCustomTypeName: '${field.type}')`;
}
else {
ofTypeStr = `ofType: ${dart_config_1.DART_AMPLIFY_CORE_TYPES.ModelFieldType}(${dart_config_1.DART_AMPLIFY_CORE_TYPES.ModelFieldTypeEnum}.collection, ofModelName: ${dart_config_1.DART_AMPLIFY_CORE_TYPES.ModelFieldTypeEnum}${ofType}.name)`;
}
}
else if (ofType === '.embedded') {
ofTypeStr = `ofType: ${dart_config_1.DART_AMPLIFY_CORE_TYPES.ModelFieldType}(${dart_config_1.DART_AMPLIFY_CORE_TYPES.ModelFieldTypeEnum}${ofType}, ofCustomTypeName: '${field.type}')`;
}
else {
ofTypeStr = `ofType: ${dart_config_1.DART_AMPLIFY_CORE_TYPES.ModelFieldType}(${dart_config_1.DART_AMPLIFY_CORE_TYPES.ModelFieldTypeEnum}${ofType})`;
}
fieldParam = [
...(ofType === '.embedded' || field.isReadOnly ? [`fieldName: '${fieldName}'`] : [`key: ${modelName}.${queryFieldName}`]),
`isRequired: ${this.isFieldRequired(field)}`,
field.isList ? 'isArray: true' : '',
field.isReadOnly ? 'isReadOnly: true' : '',
ofTypeStr,
]
.filter(f => f)
.join(',\n');
fieldsToAdd.push([
`${dart_config_1.DART_AMPLIFY_CORE_TYPES.ModelFieldDefinition}.${ofType === '.embedded' ? 'embedded' : field.isReadOnly ? 'nonQueryField' : 'field'}(`,
(0, visitor_plugin_common_1.indentMultiline)(fieldParam),
'