Skip to content

Commit

Permalink
Custom Transformer loading enhancement and fixes (aws-amplify#2814)
Browse files Browse the repository at this point in the history
* feat: enhance custom transformer loading

* fix: lint fixes

* fix: update snapshots

* feat: enhance custom transformer loading

* fix: lint fixes

* fix: update snapshots

* fix: yarn.lock update
  • Loading branch information
Attila Hajdrik authored Nov 25, 2019
1 parent 0d2d7c4 commit 886c9ee
Show file tree
Hide file tree
Showing 13 changed files with 1,047 additions and 1,125 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -476,12 +476,14 @@ async function askPaths(context, answers, currentPath) {
break;
}

addAnotherPath = (await inquirer.prompt({
name: 'anotherPath',
type: 'confirm',
message: 'Do you want to add another path?',
default: false,
})).anotherPath;
addAnotherPath = (
await inquirer.prompt({
name: 'anotherPath',
type: 'confirm',
message: 'Do you want to add another path?',
default: false,
})
).anotherPath;
} while (addAnotherPath);

const { dependsOn, functionArns } = await findDependsOn(paths, context);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ const mockContext = {};
let mockAmplify = {};
const mappedOptions1 = [{ name: 'name1', value: 'value1' }];
const mappedOptions2 = [{ name: 'name1', value: 'value1' }];
const mappedOptions3 = [{ name: 'name1', value: 'value1' }, { name: 'name2', value: 'value2' }];
const mappedOptions3 = [
{ name: 'name1', value: 'value1' },
{ name: 'name2', value: 'value2' },
];
const hostedUIProviders = [
{
name: 'prov1',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -326,9 +326,10 @@ const learnMoreLoop = async (key, map, metaData, question) => {
) {
let prefix;
if (metaData.URL) {
prefix = `\nAdditional information about the ${key} available for ${map} can be found here: ${chalkpipe(null, chalk.blue.underline)(
metaData.URL
)}\n`;
prefix = `\nAdditional information about the ${key} available for ${map} can be found here: ${chalkpipe(
null,
chalk.blue.underline
)(metaData.URL)}\n`;
prefix = prefix.concat('\n');
} else {
prefix = `\nThe following ${key} are available in ${map}\n`;
Expand Down
5 changes: 4 additions & 1 deletion packages/amplify-codegen/tests/utils/getAppSyncAPIs.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,10 @@ describe('getAppSyncAPIs', () => {
};

it('should return the projects array with name', () => {
const expectedApiList = [{ ...apiMeta.appSync1, name: 'appSync1' }, { ...apiMeta.appSync2, name: 'appSync2' }];
const expectedApiList = [
{ ...apiMeta.appSync1, name: 'appSync1' },
{ ...apiMeta.appSync2, name: 'appSync2' },
];
expect(getAppSyncAPIs(apiMeta)).toEqual(expectedApiList);
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ jest.mock('inquirer');
describe('askAppSyncAPITarget', () => {
const mockContext = 'MOCK_CONTEXT';
const selectedAPI = 'appsync-selected-api';
const appSyncAPIs = [{ name: 'api1', id: selectedAPI }, { name: 'api2', id: 'non-selected-api' }];
const appSyncAPIs = [
{ name: 'api1', id: selectedAPI },
{ name: 'api2', id: 'non-selected-api' },
];

beforeEach(() => {
jest.resetAllMocks();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ jest.mock('inquirer');

describe('Select project', () => {
const mockContext = 'CONTEXT';
const mockProjects = [{ name: 'proj1', value: 'prj-1' }, { name: 'Proj2', value: 'prj2' }];
const mockProjects = [
{ name: 'proj1', value: 'prj-1' },
{ name: 'Proj2', value: 'prj2' },
];
const selectedProject = 'prj2';

beforeEach(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ export type HeroAndFriendsNamesQuery = {
__typename: \\"Droid\\";
// The name of the character
name: string;
})
}
)
| null
> | null;
};
Expand Down Expand Up @@ -102,7 +103,8 @@ export type HeroAndFriendsNamesQuery = {
__typename: \\"Droid\\";
// The name of the character
name: string;
})
}
)
| null
> | null;
};
Expand All @@ -122,7 +124,8 @@ export type heroFriendsFragment =
__typename: \\"Droid\\";
// The name of the character
name: string;
})
}
)
| null
> | null;
}
Expand All @@ -140,7 +143,8 @@ export type heroFriendsFragment =
__typename: \\"Droid\\";
// The name of the character
name: string;
})
}
)
| null
> | null;
};
Expand Down Expand Up @@ -309,7 +313,8 @@ export type HeroAndFriendsNamesQuery = {
__typename: \\"Droid\\";
// The name of the character
name: string;
})
}
)
| null
> | null;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,7 @@ function showHostedUIURLs(context, resourcesToBeCreated) {
context.print.info(chalk`Hosted UI Endpoint: {blue.underline ${hostedUIEndpoint}}`);
const redirectURIs = oAuthMetadata.CallbackURLs.concat(oAuthMetadata.LogoutURLs);
if (redirectURIs.length > 0) {
const testHostedUIEndpoint = `https://${HostedUIDomain}.auth.${Region}.amazoncognito.com/login?response_type=code&client_id=${AppClientIDWeb}&redirect_uri=${
redirectURIs[0]
}\n`;
const testHostedUIEndpoint = `https://${HostedUIDomain}.auth.${Region}.amazoncognito.com/login?response_type=code&client_id=${AppClientIDWeb}&redirect_uri=${redirectURIs[0]}\n`;
context.print.info(chalk`Test Your Hosted UI Endpoint: {blue.underline ${testHostedUIEndpoint}}`);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const { KeyTransformer } = require('graphql-key-transformer');
const providerName = require('./constants').ProviderName;
const TransformPackage = require('graphql-transformer-core');
const { hashElement } = require('folder-hash');
const { print } = require('graphql');

const {
collectDirectivesByTypeNames,
Expand Down Expand Up @@ -66,9 +67,49 @@ function getTransformerFactory(context, resourceDir, authConfig) {
.map(transformer => {
const fileUrlMatch = /^file:\/\/(.*)\s*$/m.exec(transformer);
const modulePath = fileUrlMatch ? fileUrlMatch[1] : transformer;
// handle 'cannot find module'

if (!modulePath) {
throw new Error(`Invalid value specified for transformer: '${transformer}'`);
}

// The loading of transformer can happen multiple ways in the following order:
// - modulePath is an absolute path to an NPM package
// - modulePath is a package name, then it will be loaded from the project's root's node_modules with createRequireFromPath.
// - modulePath is a name of a globally installed package
let importedModule;
const tempModulePath = modulePath.toString();

try {
return require(modulePath);
if (path.isAbsolute(tempModulePath)) {
// Load it by absolute path
importedModule = require(modulePath);
} else {
const projectRootPath = context.amplify.pathManager.searchProjectRootPath();
const { createRequireFromPath } = require('module');
const projectRequire = createRequireFromPath(projectRootPath);

if (tempModulePath.startsWith('./')) {
// Lookup 'locally' within project's node_modules with require mechanism
importedModule = projectRequire(tempModulePath);
} else {
const prefixedModuleName = `./${tempModulePath}`;

try {
// Lookup 'locally' within project's node_modules with require mechanism
importedModule = projectRequire(prefixedModuleName);
} catch (_) {
// Intentionally left blank to try global
}

if (!importedModule) {
// Lookup in global with require
importedModule = require(tempModulePath);
}
}
}

// At this point we've to have an imported module, otherwise module loader, threw an error.
return importedModule;
} catch (error) {
context.print.error(`Unable to import custom transformer module(${modulePath}).`);
context.print.error(`You may fix this error by editing transformers at ${path.join(resourceDir, TRANSFORM_CONFIG_FILE_NAME)}`);
Expand All @@ -77,7 +118,14 @@ function getTransformerFactory(context, resourceDir, authConfig) {
})
.map(imported => {
const CustomTransformer = imported.default;
return CustomTransformer.call({});

if (typeof CustomTransformer === 'function') {
return new CustomTransformer();
} else if (typeof CustomTransformer === 'object') {
return CustomTransformer;
}

throw new Error("Custom Transformers' default export must be a function or an object");
})
.filter(customTransformer => customTransformer);

Expand Down Expand Up @@ -488,7 +536,9 @@ async function getPreviousDeploymentRootKey(previouslyDeployedBackendDir) {

async function getDirectiveDefinitions(context, resourceDir) {
const transformList = await getTransformerFactory(context, resourceDir)(true);
return transformList.map(transformPluginInst => transformPluginInst.getDirective()).join('\n');
return transformList
.map(transformPluginInst => [transformPluginInst.directive, ...transformPluginInst.typeDefinitions].map(node => print(node)).join('\n'))
.join('\n');
}

function s3ResourceAlreadyExists(context) {
Expand Down
1 change: 1 addition & 0 deletions packages/amplify-provider-awscloudformation/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"extract-zip": "^1.6.7",
"folder-hash": "^2.0.0",
"fs-extra": "^8.1.0",
"graphql": "^0.13.2",
"graphql-auth-transformer": "6.0.0",
"graphql-connection-transformer": "4.0.0",
"graphql-dynamodb-transformer": "6.0.0",
Expand Down
2 changes: 0 additions & 2 deletions packages/graphql-transformer-core/src/ITransformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,6 @@ export interface ITransformer {
acc: TransformerContext
) => void;

getDirective(): string;

/**
* A transformer implements a single function per location that its directive can be applied.
* This method handles transforming directives on object or input argument definitions.
Expand Down
6 changes: 0 additions & 6 deletions packages/graphql-transformer-core/src/Transformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@ import {
InputValueDefinitionNode,
EnumValueDefinitionNode,
TypeDefinitionNode,
DefinitionNode,
DocumentNode,
print,
} from 'graphql';
import { InvalidTransformerError } from './errors';

Expand Down Expand Up @@ -91,10 +89,6 @@ export class Transformer implements ITransformer {
acc: TransformerContext
) => void;

getDirective(): string {
return [this.directive, ...this.typeDefinitions].map(node => print(node)).join('\n');
}

/**
* A transformer implements a single function per location that its directive can be applied.
* This method handles transforming directives on object or input argument definitions.
Expand Down
Loading

0 comments on commit 886c9ee

Please sign in to comment.