UNPKG

@tobiastengler/create-relay-app

Version:

Easy configuration of Relay for existing projects

99 lines (98 loc) 3.91 kB
import generate from "@babel/generator"; import { parse } from "@babel/parser"; import t from "@babel/types"; import { format } from "prettier"; export function parseAst(code) { return parse(code, { sourceType: "module", plugins: ["typescript", "jsx"], }); } export function astToString(ast, oldCode) { return generate.default(ast, { retainLines: true }, oldCode).code; } export function printAst(ast, oldCode) { const newCode = astToString(ast, oldCode); return prettifyCode(newCode); } export function prettifyCode(code) { return format(code, { bracketSameLine: false, endOfLine: "auto", parser: "babel-ts", }); } export function insertNamedImport(path, importName, packageName) { return insertNamedImports(path, [importName], packageName)[0]; } export function insertNamedImports(path, imports, packageName) { const program = path.findParent((p) => p.isProgram()); const identifiers = []; const missingImports = []; for (const namedImport of imports) { const importIdentifier = t.identifier(namedImport); const existingImport = getNamedImport(program, namedImport, packageName); if (!!existingImport) { identifiers.push(importIdentifier); continue; } missingImports.push(namedImport); } let importDeclaration; const isFirstImportFromPackage = missingImports.length === imports.length; if (isFirstImportFromPackage) { importDeclaration = t.importDeclaration([], t.stringLiteral(packageName)); } else { importDeclaration = getImportDeclaration(program, packageName); } for (const namedImport of missingImports) { const importIdentifier = t.identifier(namedImport); const newImport = t.importSpecifier(t.cloneNode(importIdentifier), importIdentifier); importDeclaration.specifiers.push(newImport); identifiers.push(importIdentifier); } if (isFirstImportFromPackage) { // Insert import at start of file. program.node.body.unshift(importDeclaration); } return identifiers; } export function insertDefaultImport(path, importName, packageName) { const importIdentifier = t.identifier(importName); const program = path.findParent((p) => p.isProgram()); const existingImport = getDefaultImport(program, importName, packageName); if (!!existingImport) { return importIdentifier; } const importDeclaration = t.importDeclaration([t.importDefaultSpecifier(t.cloneNode(importIdentifier))], t.stringLiteral(packageName)); // Insert import at start of file. program.node.body.unshift(importDeclaration); return importIdentifier; } function getImportDeclaration(path, packageName) { return path.node.body.find((s) => t.isImportDeclaration(s) && s.source.value === packageName); } export function getNamedImport(path, importName, packageName) { return path.node.body.find((s) => t.isImportDeclaration(s) && s.source.value === packageName && s.specifiers.some((sp) => t.isImportSpecifier(sp) && sp.local.name === importName)); } function getDefaultImport(path, importName, packageName) { return path.node.body.find((s) => t.isImportDeclaration(s) && s.source.value === packageName && s.specifiers.some((sp) => t.isImportDefaultSpecifier(sp) && sp.local.name === importName)); } export function mergeProperties(existingProps, newProps) { let existingCopy = [...existingProps]; for (const prop of newProps) { const existingIndex = existingCopy.findIndex((p) => t.isObjectProperty(p) && t.isIdentifier(p.key) && t.isIdentifier(prop.key) && p.key.name === prop.key.name); if (existingIndex !== -1) { existingCopy[existingIndex] = prop; } else { existingCopy.push(prop); } } return existingCopy; }