amplify-codegen
Version:
Amplify Code Generator
157 lines (145 loc) • 6.36 kB
JavaScript
const path = require('path');
const fs = require('fs-extra');
const Ora = require('ora');
const globby = require('globby');
const { Source } = require('graphql');
const constants = require('../constants');
const { loadConfig } = require('../codegen-config');
const { ensureIntrospectionSchema, getFrontEndHandler, getAppSyncAPIDetails, getAppSyncAPIInfoFromProject } = require('../utils');
const { generateTypes: generateTypesHelper } = require('@aws-amplify/graphql-generator');
const { extractDocumentFromJavascript } = require('@aws-amplify/graphql-types-generator');
const { normalizePathForGlobPattern } = require('../utils/input-params-manager');
async function generateTypes(context, forceDownloadSchema, withoutInit = false, decoupleFrontend = '') {
let frontend = decoupleFrontend;
try {
context.amplify.getProjectMeta();
} catch (e) {
withoutInit = true;
}
if (!withoutInit) {
frontend = getFrontEndHandler(context);
}
if (frontend !== 'android') {
const config = loadConfig(context, withoutInit);
const projects = config.getProjects();
if (!projects.length && withoutInit) {
context.print.info(constants.ERROR_CODEGEN_NO_API_CONFIGURED);
return;
}
let apis = [];
if (!withoutInit) {
apis = getAppSyncAPIDetails(context);
} else {
const api = await getAppSyncAPIInfoFromProject(context, projects[0]);
if (api) {
apis = [api];
}
}
if (!projects.length || !apis.length) {
if (!withoutInit) {
context.print.info(constants.ERROR_CODEGEN_NO_API_CONFIGURED);
return;
}
}
let projectPath = process.cwd();
if (!withoutInit) {
({ projectPath } = context.amplify.getEnvInfo());
}
try {
for (const cfg of projects) {
const { generatedFileName } = cfg.amplifyExtension || {};
const includeFiles = cfg.includes;
if (!generatedFileName || generatedFileName === '' || includeFiles.length === 0) {
return;
}
const target = cfg.amplifyExtension.codeGenTarget;
let amplifyJsLibraryVersion = cfg.amplifyExtension.amplifyJsLibraryVersion;
/**
* amplifyJsLibraryVersion config is currently used for angular codegen
* The supported value is 5 for JS v5 and 6 for JS v6
* When the value is undefined, it will stay at codegen for JS v5 for non-breaking change for existing users
* For the other values set, a warning message will be sent in the console and the codegen will use the v6 codegen
*/
if (target === 'angular' && amplifyJsLibraryVersion && amplifyJsLibraryVersion !== 6 && amplifyJsLibraryVersion !== 5) {
context.print.warning(
`Amplify JS library version ${amplifyJsLibraryVersion} is not supported. The current support JS library version is [5, 6]. Codegen will be executed for JS v6 instead.`,
);
amplifyJsLibraryVersion = 6
}
const excludes = cfg.excludes.map(pattern => `!${pattern}`);
const normalizedPatterns = [...includeFiles, ...excludes].map((path) => normalizePathForGlobPattern(path));
const queryFilePaths = globby.sync(normalizedPatterns, {
cwd: projectPath,
absolute: true,
});
const queries = queryFilePaths
.map(queryFilePath => {
const fileContents = fs.readFileSync(queryFilePath, 'utf8');
if (
queryFilePath.endsWith('.jsx') ||
queryFilePath.endsWith('.js') ||
queryFilePath.endsWith('.tsx') ||
queryFilePath.endsWith('.ts')
) {
return [queryFilePath, extractDocumentFromJavascript(fileContents, '')];
}
return [queryFilePath, new Source(fileContents, queryFilePath)];
})
.filter(([queryFilePath, source]) => {
if (!source) {
context.print.warning(
`Unable to extract GraphQL queries from ${queryFilePath}. Skipping source. This source matched the includes target in .grapqhlconfig.yml. Modify the includes or excludes target if this file should not be included.`,
);
return false;
}
return true;
})
.map(([, source]) => source);
if (queries.length === 0) {
throw new Error("No queries found to generate types for, you may need to run 'codegen statements' first");
}
const schemaPath = path.join(projectPath, cfg.schema);
const outputPath = path.join(projectPath, generatedFileName);
if (apis.length) {
const { region } = cfg.amplifyExtension;
await ensureIntrospectionSchema(context, schemaPath, apis[0], region, forceDownloadSchema);
} else {
if (!fs.existsSync(schemaPath)) {
throw new Error(`Cannot find GraphQL schema file: ${schemaPath}`);
}
}
const codeGenSpinner = new Ora(constants.INFO_MESSAGE_CODEGEN_GENERATE_STARTED);
codeGenSpinner.start();
const schema = fs.readFileSync(schemaPath, 'utf8');
const introspection = path.extname(schemaPath) === '.json';
const multipleSwiftFiles = target === 'swift' && fs.existsSync(outputPath) && fs.statSync(outputPath).isDirectory();
try {
const output = await generateTypesHelper({
schema,
queries,
target,
introspection,
multipleSwiftFiles,
amplifyJsLibraryVersion,
});
const outputs = Object.entries(output);
const outputPath = path.join(projectPath, generatedFileName);
if (outputs.length === 1) {
const [[, contents]] = outputs;
fs.outputFileSync(path.resolve(outputPath), contents);
} else {
outputs.forEach(([filepath, contents]) => {
fs.outputFileSync(path.resolve(path.join(outputPath, filepath)), contents);
});
}
codeGenSpinner.succeed(`${constants.INFO_MESSAGE_CODEGEN_GENERATE_SUCCESS} ${path.relative(path.resolve('.'), outputPath)}`);
} catch (err) {
codeGenSpinner.fail(err.message);
}
}
} catch (err) {
throw Error(err.message);
}
}
}
module.exports = generateTypes;