UNPKG

@aws-amplify/cli-internal

Version:
205 lines • 10.3 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.DataGenerator = exports.classifyVtlFiles = exports.parseVtlFilename = void 0; const node_path_1 = __importDefault(require("node:path")); const promises_1 = __importDefault(require("node:fs/promises")); const node_fs_1 = require("node:fs"); const glob_1 = require("glob"); const amplify_cli_core_1 = require("@aws-amplify/amplify-cli-core"); const ts_1 = require("../../ts"); const data_renderer_1 = require("./data.renderer"); function parseVtlFilename(filename) { const segments = filename.split('.'); if (segments.length === 4) { const [typeName, fieldName, templateType] = segments; return { kind: 'override', typeName, fieldName, templateType: templateType, filename, }; } if (segments.length === 6) { const [typeName, fieldName, slot, orderStr, templateType] = segments; return { kind: 'extended', typeName, fieldName, slot, order: Number(orderStr), templateType: templateType, filename, }; } return undefined; } exports.parseVtlFilename = parseVtlFilename; function classifyVtlFiles(filenames) { const overrides = []; const extended = []; const seen = new Map(); for (const filename of filenames) { const parsed = parseVtlFilename(filename); if (!parsed) continue; if (parsed.kind === 'override') { overrides.push(parsed); } else { const segments = filename.split('.'); const orderStr = segments[3]; if (!/^\d+$/.test(orderStr)) { throw new Error(`Non-numeric order '${orderStr}' in extended resolver file '${filename}'`); } const key = `${parsed.typeName}.${parsed.fieldName}.${parsed.slot}.${parsed.order}.${parsed.templateType}`; const existing = seen.get(key); if (existing) { throw new Error(`Duplicate extended resolver: '${existing}' and '${filename}'`); } seen.set(key, filename); extended.push(parsed); } } return { overrides, extended }; } exports.classifyVtlFiles = classifyVtlFiles; class DataGenerator { constructor(gen1App, backendGenerator, outputDir, resource, logger) { this.gen1App = gen1App; this.backendGenerator = backendGenerator; this.outputDir = outputDir; this.resource = resource; this.renderer = new data_renderer_1.DataRenderer(gen1App.envName); this.logger = logger; } async plan() { const schema = this.collectUserSchema(); const apiId = this.gen1App.resourceMetaOutput(this.resource, 'GraphQLAPIIdOutput'); const tableMappings = this.createTableMappings(apiId); this.logger.debug(`Fetching AppSync API '${apiId}'`); const graphqlApi = await this.gen1App.aws.fetchGraphqlApi(apiId); if (!graphqlApi) { throw new amplify_cli_core_1.AmplifyError('AppSyncApiNotFoundError', { message: `AppSync API '${apiId}' not found`, resolution: 'Verify the AppSync API exists and the CLI has the correct AWS credentials and region configured.', }); } const dataDir = node_path_1.default.join(this.outputDir, 'amplify', 'data'); const hasAdditionalAuthProviders = graphqlApi.additionalAuthenticationProviders !== undefined && graphqlApi.additionalAuthenticationProviders.length > 0; const hasAuth = this.gen1App.categoryMeta('auth') !== undefined; const authorizationModes = supplementOidcConfig(this.gen1App.resourceMetaOutput(this.resource, 'authConfig'), graphqlApi); const hasIamAuth = this.detectIamAuth(authorizationModes, graphqlApi); const vtlFiles = this.findResolverVtlFiles(this.resource.resourceName); const hasResolvers = vtlFiles.length > 0; const classifiedResolvers = hasResolvers ? classifyVtlFiles([...vtlFiles]) : undefined; const needsEscapeHatches = hasAdditionalAuthProviders || (hasIamAuth && hasAuth) || hasResolvers; const operations = [ { resource: this.resource, validate: () => undefined, describe: async () => ['Generate amplify/data/resource.ts'], execute: async () => { this.logger.info('Rendering data/resource.ts'); const nodes = this.renderer.render({ schema, tableMappings, authorizationModes, graphqlApi, hasAuth, apiId, classifiedResolvers, }); const content = ts_1.TS.printNodes(nodes); await promises_1.default.mkdir(dataDir, { recursive: true }); await promises_1.default.writeFile(node_path_1.default.join(dataDir, 'resource.ts'), content, 'utf-8'); this.backendGenerator.addNamespaceImport('data', './data/resource'); this.backendGenerator.addDefineBackendEntry('data', 'data', 'data'); if (needsEscapeHatches) { this.backendGenerator.addApplyEscapeHatchesCall({ alias: 'data', extraArgs: [] }); } }, }, ]; if (hasResolvers) { const gen1ResolversDir = node_path_1.default.join(this.gen1App.ccbDir, 'api', this.resource.resourceName, 'resolvers'); const destResolversDir = node_path_1.default.join(dataDir, 'resolvers'); operations.push({ resource: this.resource, validate: () => undefined, describe: async () => ['Copy VTL resolver files to amplify/data/resolvers/'], execute: async () => { await promises_1.default.mkdir(destResolversDir, { recursive: true }); for (const file of vtlFiles) { await promises_1.default.copyFile(node_path_1.default.join(gen1ResolversDir, file), node_path_1.default.join(destResolversDir, file)); } }, }); } return operations; } collectUserSchema() { const schemaFilePath = node_path_1.default.join('api', this.resource.resourceName, 'schema.graphql'); if (this.gen1App.fileExists(schemaFilePath)) { return this.gen1App.file(schemaFilePath); } const schemaDirPath = node_path_1.default.join('api', this.resource.resourceName, 'schema'); const fullDirPath = node_path_1.default.join(this.gen1App.ccbDir, schemaDirPath); const files = (0, glob_1.globSync)('**/*.graphql', { cwd: fullDirPath }).sort(); return files.map((f) => this.gen1App.file(node_path_1.default.join(schemaDirPath, f))).join('\n'); } findResolverVtlFiles(apiName) { const resolversDir = node_path_1.default.join(this.gen1App.ccbDir, 'api', apiName, 'resolvers'); if (!(0, node_fs_1.existsSync)(resolversDir)) { return []; } return (0, node_fs_1.readdirSync)(resolversDir).filter((f) => f.endsWith('.vtl')); } createTableMappings(apiId) { const buildSchemaPath = node_path_1.default.join('api', this.resource.resourceName, 'build', 'schema.graphql'); const buildSchema = this.gen1App.file(buildSchemaPath); const connectionRegex = /type\s+Model(\w+)Connection\b/g; const mapping = {}; let match; while ((match = connectionRegex.exec(buildSchema)) !== null) { mapping[match[1]] = [match[1], apiId, this.gen1App.envName].join('-'); } return mapping; } detectIamAuth(authorizationModes, graphqlApi) { var _a, _b, _c; const defaultAuthType = (_a = authorizationModes === null || authorizationModes === void 0 ? void 0 : authorizationModes.defaultAuthentication) === null || _a === void 0 ? void 0 : _a.authenticationType; if (defaultAuthType === 'AWS_IAM') return true; return (_c = (_b = graphqlApi.additionalAuthenticationProviders) === null || _b === void 0 ? void 0 : _b.some((p) => p.authenticationType === 'AWS_IAM')) !== null && _c !== void 0 ? _c : false; } } exports.DataGenerator = DataGenerator; function supplementOidcConfig(authConfig, graphqlApi) { var _a, _b, _c, _d; if (!authConfig) return authConfig; const result = JSON.parse(JSON.stringify(authConfig)); if (((_a = result.defaultAuthentication) === null || _a === void 0 ? void 0 : _a.authenticationType) === 'OPENID_CONNECT' && result.defaultAuthentication.openIDConnectConfig && !result.defaultAuthentication.openIDConnectConfig.clientId && ((_b = graphqlApi.openIDConnectConfig) === null || _b === void 0 ? void 0 : _b.clientId)) { result.defaultAuthentication.openIDConnectConfig.clientId = graphqlApi.openIDConnectConfig.clientId; } if (result.additionalAuthenticationProviders) { for (const provider of result.additionalAuthenticationProviders) { if (provider.authenticationType !== 'OPENID_CONNECT' || !provider.openIDConnectConfig || provider.openIDConnectConfig.clientId) { continue; } const match = (_c = graphqlApi.additionalAuthenticationProviders) === null || _c === void 0 ? void 0 : _c.find((p) => { var _a; return p.authenticationType === 'OPENID_CONNECT' && ((_a = p.openIDConnectConfig) === null || _a === void 0 ? void 0 : _a.issuer) === provider.openIDConnectConfig.issuerUrl; }); if ((_d = match === null || match === void 0 ? void 0 : match.openIDConnectConfig) === null || _d === void 0 ? void 0 : _d.clientId) { provider.openIDConnectConfig.clientId = match.openIDConnectConfig.clientId; } } } return result; } //# sourceMappingURL=data.generator.js.map