diff --git a/packages/amplify-codegen/src/commands/models.js b/packages/amplify-codegen/src/commands/models.js index 45bfa220e..837e2b8d4 100644 --- a/packages/amplify-codegen/src/commands/models.js +++ b/packages/amplify-codegen/src/commands/models.js @@ -7,30 +7,13 @@ const { validateAmplifyFlutterMinSupportedVersion } = require('../utils/validate const defaultDirectiveDefinitions = require('../utils/defaultDirectiveDefinitions'); const getModelSchemaPathParam = require('../utils/getModelSchemaPathParam'); -/** - * Returns feature flag value, default to `false` - * @param {!string} key feature flag id - * @returns {string} the feature flag value - */ -const readFeatureFlag = (key) => { - try { - return FeatureFlags.getBoolean(key); - } catch (_) { - return false; - } -}; - -/** - * Returns feature flag value, default to `1` - * @param {!string} key feature flag id - * @returns {number} the feature flag value - */ -const readNumericFeatureFlag = (key) => { - try { - return FeatureFlags.getNumber(key); - } catch (_) { - return 1; - } +const frontendToTargetMap = { + android: 'java', + ios: 'swift', + flutter: 'dart', + javascript: 'javascript', + typescript: 'typescript', + introspection: 'introspection', }; // type GenerateModelsOptions = { @@ -127,7 +110,7 @@ const getOutputPath = (context, overrideOutputDir, projectRoot) => { * @param {!boolean} isIntrospection whether or not this is a request for an introspection model. * @returns {!import('@aws-amplify/appsync-modelgen-plugin').Target} the Modelgen target as a string */ -const getTarget = (context, isIntrospection) => { +const getFrontend = (context, isIntrospection) => { if (isIntrospection) { return 'introspection'; } @@ -146,21 +129,27 @@ const getTarget = (context, isIntrospection) => { * @param {!string} flagName the feature flag name * @returns {boolean | null} the feature flag value if found, and can be coerced to a boolean, else null */ -const getOptionBasedFeatureFlag = (context, flagName) => { +const getBooleanFeatureFlag = (context, flagName) => { + // Attempt to read from cli input options as overrides first.~ const featureFlagParamName = `feature-flag:${flagName}`; const paramNames = context.parameters?.options ? new Set(Object.keys(context.parameters?.options)) : new Set(); - if (!paramNames.has(featureFlagParamName)) { - return null; + if (paramNames.has(featureFlagParamName)) { + const optionValue = context.parameters?.options?.[featureFlagParamName]; + if (optionValue === 'true' || optionValue === 'True' || optionValue === true) { + return true; + } + if (optionValue === 'false' || optionValue === 'False' || optionValue === false) { + return false; + } + throw new Error(`Feature flag value for parameter ${featureFlagParamName} could not be marshalled to boolean type, found ${optionValue}`); } - const optionValue = context.parameters?.options?.[featureFlagParamName]; - if (optionValue === 'true' || optionValue === 'True' || optionValue === true) { - return true; - } - if (optionValue === 'false' || optionValue === 'False' || optionValue === false) { + // Read from feature flag file, fall back to false if nothing is found, and no default exists in-system. + try { + return FeatureFlags.getBoolean(flagName); + } catch (_) { return false; } - return null; }; /** @@ -169,45 +158,32 @@ const getOptionBasedFeatureFlag = (context, flagName) => { * @param {!string} flagName the feature flag name * @returns {number | null} the feature flag value if found, and can be coerced to an int, else null */ -const getOptionBasedNumericFeatureFlag = (context, flagName) => { +const getNumericFeatureFlag = (context, flagName) => { + // Attempt to read from cli input options as overrides first. const featureFlagParamName = `feature-flag:${flagName}`; const paramNames = context.parameters?.options ? new Set(Object.keys(context.parameters?.options)) : new Set(); - if (!paramNames.has(featureFlagParamName)) { - return null; + if (paramNames.has(featureFlagParamName)) { + const optionValue = context.parameters?.options?.[featureFlagParamName]; + return Number.parseInt(optionValue, 10); } - const optionValue = context.parameters?.options?.[featureFlagParamName]; - return Number.parseInt(optionValue, 10); -}; - -/** - * Retrieve the feature flags either using sane defaults, or an amplify feature flags file. - * @param {*} context the amplify runtime context - * @returns {({ generateIndexRules: boolean, emitAuthProvider: boolean, useExperimentalPipelinedTransformer: boolean, transformerVersion: number, respectPrimaryKeyAttributesOnConnectionField: boolean, generateModelsForLazyLoadAndCustomSelectionSet: boolean, improvePluralization: boolean, addTimestampFields: boolean, handleListNullabilityTransparently: boolean })} the feature flags to provide to the generator - */ -const getFeatureFlags = (context) => { - return { - generateIndexRules: getOptionBasedFeatureFlag(context, 'codegen.generateIndexRules') ?? readFeatureFlag('codegen.generateIndexRules'), - emitAuthProvider: getOptionBasedFeatureFlag(context, 'codegen.emitAuthProvider') ?? readFeatureFlag('codegen.emitAuthProvider'), - useExperimentalPipelinedTransformer: getOptionBasedFeatureFlag(context, 'graphQLTransformer.useExperimentalPipelinedTransformer') ?? readFeatureFlag('graphQLTransformer.useExperimentalPipelinedTransformer'), - transformerVersion: getOptionBasedNumericFeatureFlag(context, 'graphQLTransformer.transformerVersion') ?? readNumericFeatureFlag('graphQLTransformer.transformerVersion'), - respectPrimaryKeyAttributesOnConnectionField: getOptionBasedFeatureFlag(context, 'graphQLTransformer.respectPrimaryKeyAttributesOnConnectionField') ?? readFeatureFlag('graphQLTransformer.respectPrimaryKeyAttributesOnConnectionField'), - generateModelsForLazyLoadAndCustomSelectionSet: getOptionBasedFeatureFlag(context, 'codegen.generateModelsForLazyLoadAndCustomSelectionSet') ?? readFeatureFlag('codegen.generateModelsForLazyLoadAndCustomSelectionSet'), - improvePluralization: getOptionBasedFeatureFlag(context, 'graphQLTransformer.improvePluralization') ?? readFeatureFlag('graphQLTransformer.improvePluralization'), - addTimestampFields: getOptionBasedFeatureFlag(context, 'codegen.addTimestampFields') ?? readFeatureFlag('codegen.addTimestampFields'), - handleListNullabilityTransparently: getOptionBasedFeatureFlag(context, 'codegen.handleListNullabilityTransparently') ?? readFeatureFlag('codegen.handleListNullabilityTransparently'), - }; + // Read from feature flag file, fall back to '1' if nothing is found, and no default exists in-system. + try { + return FeatureFlags.getNumber(flagName); + } catch (_) { + return 1; + } }; /** * Run validations over the project state, return the errors of an array of strings. * @param {!string} projectRoot the project root path for validating local state - * @param {!import('@aws-amplify/appsync-modelgen-plugin').Target} target the runtime target we are running modelgen for. + * @param {!string} frontend the frontend being targeted for this project. * @returns {Array} the list of validation failures detected */ -const validateProjectState = (projectRoot, target) => { +const validateProjectState = (projectRoot, frontend) => { const validationFailures = []; - if (target === 'flutter' && !validateAmplifyFlutterMinSupportedVersion(projectRoot)) { + if (frontend === 'flutter' && !validateAmplifyFlutterMinSupportedVersion(projectRoot)) { validationFailures.push(`🚫 Models are not generated! Amplify Flutter versions prior to 0.6.0 are no longer supported by codegen. Please upgrade to use codegen.`); } @@ -228,30 +204,28 @@ async function generateModels(context, generateOptions = null) { await validateSchema(context); const schema = loadSchema(modelSchemaPath); - const target = getTarget(context, isIntrospection); + const frontend = getFrontend(context, isIntrospection); - const validationFailures = validateProjectState(projectRoot, target); + const validationFailures = validateProjectState(projectRoot, frontend); if (validationFailures.length > 0) { validationFailures.forEach((validationFailure) => context.print.error(validationFailure)); return; } - const { - generateIndexRules, - emitAuthProvider, - useExperimentalPipelinedTransformer, - transformerVersion, - respectPrimaryKeyAttributesOnConnectionField, - generateModelsForLazyLoadAndCustomSelectionSet, - improvePluralization, - addTimestampFields, - handleListNullabilityTransparently, - } = getFeatureFlags(context); + const generateIndexRules = getBooleanFeatureFlag(context, 'codegen.generateIndexRules'); + const emitAuthProvider = getBooleanFeatureFlag(context, 'codegen.emitAuthProvider'); + const useExperimentalPipelinedTransformer = getBooleanFeatureFlag(context, 'graphQLTransformer.useExperimentalPipelinedTransformer'); + const transformerVersion = getNumericFeatureFlag(context, 'graphQLTransformer.transformerVersion'); + const respectPrimaryKeyAttributesOnConnectionField = getBooleanFeatureFlag(context, 'graphQLTransformer.respectPrimaryKeyAttributesOnConnectionField'); + const generateModelsForLazyLoadAndCustomSelectionSet = getBooleanFeatureFlag(context, 'codegen.generateModelsForLazyLoadAndCustomSelectionSet'); + const improvePluralization = getBooleanFeatureFlag(context, 'graphQLTransformer.improvePluralization'); + const addTimestampFields = getBooleanFeatureFlag(context, 'codegen.addTimestampFields'); + const handleListNullabilityTransparently = getBooleanFeatureFlag(context, 'codegen.handleListNullabilityTransparently'); const generatedCode = await generateModelsHelper({ schema, directives, - target, + target: frontendToTargetMap[frontend], generateIndexRules, emitAuthProvider, useExperimentalPipelinedTransformer, @@ -274,7 +248,7 @@ async function generateModels(context, generateOptions = null) { try { // TODO: move to @aws-amplify/graphql-generator - generateEslintIgnore(context, target); + generateEslintIgnore(context, frontend); } catch (e) {} context.print.info(`Successfully generated models. Generated models can be found in ${outputPath}`); @@ -342,8 +316,8 @@ function getModelOutputPath(context) { } } -const generateEslintIgnore = (context, target) => { - if (target !== 'javascript') { +const generateEslintIgnore = (context, frontend) => { + if (frontend !== 'javascript') { return; } diff --git a/packages/amplify-codegen/src/utils/getOutputDirParam.js b/packages/amplify-codegen/src/utils/getOutputDirParam.js index ec4fd8495..1bbf02e8f 100644 --- a/packages/amplify-codegen/src/utils/getOutputDirParam.js +++ b/packages/amplify-codegen/src/utils/getOutputDirParam.js @@ -17,7 +17,6 @@ function getOutputDirParam(context, isRequired) { } let projectRoot; try { - context.amplify.getProjectMeta(); projectRoot = context.amplify.getEnvInfo().projectPath; } catch (e) { projectRoot = process.cwd();