Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
directiveList.forEach((value: DirectiveNode) => {
const url = getDirectiveArgument(value, 'url');
// require a protocol in the url
const protocolMatcher = /^http(s)?:\/\//;
if (!protocolMatcher.test(url)) {
throw new TransformerContractError(
`@http directive at location ${value.loc.start} ` + `requires a url parameter that begins with http:// or https://.`
);
}
// extract just the base url with protocol
const baseURL = url.replace(HttpTransformer.urlRegex, '$1');
const dataSourceID = HttpResourceIDs.HttpDataSourceID(baseURL);
// only create one DataSource per base URL
if (!ctx.getResource(dataSourceID)) {
ctx.mapResourceToStack(HTTP_STACK_NAME, dataSourceID);
ctx.setResource(dataSourceID, this.resources.makeHttpDataSource(baseURL));
}
});
};
]
// Only insert certain plugins if needed, otherwise they pollute the cloudformation
// for no good reason.
// We determine if needed with a simple string search for the directive string
function conditionalInsertDirectivePlugin(plugin, searchString){
if (schema.indexOf(searchString) >= 0) {
transformers.push(plugin)
}
}
conditionalInsertDirectivePlugin(new ModelAuthTransformer(), '@auth');
conditionalInsertDirectivePlugin(new SearchableModelTransformer(), '@searchable');
// console.log(process.argv)
const transformer = new GraphQLTransform({
transformers: transformers
})
const cfdoc = transformer.transform(schema);
console.log(JSON.stringify(cfdoc, null, 2))
function validateKeyField(field: FieldDefinitionNode): void {
if (!field) {
return
}
const isNonNull = isNonNullType(field.type);
const isAList = isListType(field.type)
// The only valid key fields are single non-null fields.
if (!isAList && isNonNull) {
return;
}
throw new InvalidDirectiveError(`All fields used for a relation cannot be lists and must be of Non-Null types.`)
}
for (const otherDirective of definition.directives.filter(d => d.name.value === 'key')) {
const otherArgs = getDirectiveArguments(otherDirective);
if (otherDirective !== directive && !otherArgs.name) {
throw new InvalidDirectiveError(`You may only supply one primary @key on type '${definition.name.value}'.`);
}
// 5. If there is no primary sort key, make sure there are no more LSIs.
const hasPrimarySortKey = directiveArgs.fields.length > 1;
const primaryHashField = directiveArgs.fields[0];
const otherHashField = otherArgs.fields[0];
if (
otherDirective !== directive &&
!hasPrimarySortKey &&
// If the primary key and other key share the first field and are not the same directive it is an LSI.
primaryHashField === otherHashField
) {
throw new InvalidDirectiveError(
`Invalid @key "${otherArgs.name}". You may not create a @key where the first field in 'fields' ` +
`is the same as that of the primary @key unless the primary @key has multiple 'fields'. ` +
`You cannot have a local secondary index without a sort key in the primary index.`
);
}
}
// 4. Make sure that a 'queryField' is not included on a primary @key.
if (directiveArgs.queryField) {
throw new InvalidDirectiveError(`You cannot pass 'queryField' to the primary @key on type '${definition.name.value}'.`);
}
} else {
// 2. Make sure there are no more directives with the same name.
for (const otherDirective of definition.directives.filter(d => d.name.value === 'key')) {
const otherArgs = getDirectiveArguments(otherDirective);
if (otherDirective !== directive && otherArgs.name === directiveArgs.name) {
throw new InvalidDirectiveError(`You may only supply one @key with the name '${directiveArgs.name}' on type '${definition.name.value}'.`);
function validateKeyField(field: FieldDefinitionNode): void {
if (!field) {
return
}
const baseType = getBaseType(field.type);
const isAList = isListType(field.type)
// The only valid key fields are single String and ID fields.
if (
(baseType === 'ID' || baseType === 'String') &&
(!isAList)
) {
return;
}
throw new InvalidDirectiveError(`If you define a field and specify it as a 'keyField', it must be of type 'ID' or 'String'.`)
}
public object = (def: ObjectTypeDefinitionNode, directive: DirectiveNode, ctx: TransformerContext): void => {
const get = (s: string) => (arg: ArgumentNode) => arg.name.value === s
const getArg = (arg: string, dflt?: any) => {
const argument = directive.arguments.find(get(arg))
return argument ? valueFromASTUntyped(argument.value) : dflt
}
const modelDirective = def.directives.find((dir) => dir.name.value === 'model')
if (!modelDirective) {
throw new InvalidDirectiveError('Types annotated with @auth must also be annotated with @model.')
}
// Get and validate the auth rules.
const rules = getArg('rules', []) as AuthRule[]
this.validateRules(rules)
const { operationRules, queryRules } = this.splitRules(rules);
// For each operation evaluate the rules and apply the changes to the relevant resolver.
this.protectCreateMutation(ctx, ResolverResourceIDs.DynamoDBCreateResolverResourceID(def.name.value), operationRules.create, def)
this.protectUpdateMutation(ctx, ResolverResourceIDs.DynamoDBUpdateResolverResourceID(def.name.value), operationRules.update, def)
this.protectDeleteMutation(ctx, ResolverResourceIDs.DynamoDBDeleteResolverResourceID(def.name.value), operationRules.delete, def)
this.protectGetQuery(ctx, ResolverResourceIDs.DynamoDBGetResolverResourceID(def.name.value), queryRules.get)
this.protectListQuery(ctx, ResolverResourceIDs.DynamoDBListResolverResourceID(def.name.value), queryRules.list)
this.protectConnections(ctx, def, operationRules.read)
this.protectQueries(ctx, def, operationRules.read)
private createMutations = (
def: ObjectTypeDefinitionNode,
directive: DirectiveNode,
ctx: TransformerContext,
nonModelArray: ObjectTypeDefinitionNode[]
) => {
const typeName = def.name.value
const mutationFields = [];
// Get any name overrides provided by the user. If an empty map it provided
// then we do not generate those fields.
const directiveArguments: ModelDirectiveArgs = getDirectiveArguments(directive)
// Configure mutations based on *mutations* argument
let shouldMakeCreate = true;
let shouldMakeUpdate = true;
let shouldMakeDelete = true;
let createFieldNameOverride = undefined;
let updateFieldNameOverride = undefined;
let deleteFieldNameOverride = undefined;
// Figure out which mutations to make and if they have name overrides
if (directiveArguments.mutations === null) {
shouldMakeCreate = false
shouldMakeUpdate = false
shouldMakeDelete = false
} else if (directiveArguments.mutations) {
private createSubscriptions = (def: ObjectTypeDefinitionNode, directive: DirectiveNode, ctx: TransformerContext) => {
const typeName = def.name.value
const subscriptionFields = []
const directiveArguments: ModelDirectiveArgs = getDirectiveArguments(directive)
const subscriptionsArgument = directiveArguments.subscriptions
const createResolver = ctx.getResource(ResolverResourceIDs.DynamoDBCreateResolverResourceID(typeName))
const updateResolver = ctx.getResource(ResolverResourceIDs.DynamoDBUpdateResolverResourceID(typeName))
const deleteResolver = ctx.getResource(ResolverResourceIDs.DynamoDBDeleteResolverResourceID(typeName))
if (subscriptionsArgument === null) {
return;
} else if (subscriptionsArgument &&
subscriptionsArgument.level === "OFF") {
return;
} else if (subscriptionsArgument &&
subscriptionsArgument.level !== "PUBLIC") {
// Add the custom subscriptions
const subscriptionToMutationsMap: { [subField: string]: string[] } = {}
const onCreate = subscriptionsArgument.onCreate || []
const onUpdate = subscriptionsArgument.onUpdate || []
public newParameterization = (
parent: ObjectTypeDefinitionNode | InterfaceTypeDefinitionNode,
field: FieldDefinitionNode,
directive: DirectiveNode,
ctx: TransformerContext
): void => {
const parentTypeName = parent.name.value;
const fieldName = field.name.value;
const args : RelationArguments = getDirectiveArguments(directive);
const numFields = args.fields.length;
// Check that related type exists and that the connected object is annotated with @model.
const relatedTypeName = getBaseType(field.type)
const relatedType = ctx.inputDocument.definitions.find(
d => d.kind === Kind.OBJECT_TYPE_DEFINITION && d.name.value === relatedTypeName
) as ObjectTypeDefinitionNode | undefined
// Get Child object's table.
const tableLogicalID = ModelResourceIDs.ModelTableResourceID(relatedType.name.value);
const tableResource = ctx.getResource(tableLogicalID) as Table;
// Ensure that there is at least one field provided.
if (numFields === 0) {
throw new InvalidDirectiveError('No fields passed in to @connection directive.')
}
private protectQueries(ctx: TransformerContext, def: ObjectTypeDefinitionNode, rules: AuthRule[]) {
const secondaryKeyDirectivesWithQueries = (def.directives || []).filter(d => {
const isKey = d.name.value === 'key';
const args = getDirectiveArguments(d);
// @key with a name is a secondary key.
const isSecondaryKey = Boolean(args.name);
const hasQueryField = Boolean(args.queryField);
return isKey && isSecondaryKey && hasQueryField;
});
for (const keyWithQuery of secondaryKeyDirectivesWithQueries) {
const args = getDirectiveArguments(keyWithQuery);
const resolverResourceId = ResolverResourceIDs.ResolverResourceID(ctx.getQueryTypeName(), args.queryField);
this.protectListQuery(ctx, resolverResourceId, rules)
}
}