Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@tobiastengler/create-relay-app

Package Overview
Dependencies
Maintainers
1
Versions
24
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@tobiastengler/create-relay-app - npm Package Compare versions

Comparing version 0.0.0-experimental-c4ec8b793 to 0.0.0-experimental-e6e505b7a

assets/env

131

dist/bin.js
#!/usr/bin/env node
import path from "path";
import path, { dirname } from "path";
import { TaskRunner } from "./TaskRunner.js";

@@ -7,25 +7,39 @@ import { AddGraphQlSchemaFileTask } from "./tasks/AddGraphQlSchemaFileTask.js";

import { AddRelayConfigurationTask } from "./tasks/AddRelayConfigurationTask.js";
import inquirer from "inquirer";
import { ToolChainOptions, LanguageOptions, PackageManagerOptions, } from "./types.js";
import { InstallNpmPackagesTask } from "./tasks/InstallNpmPackagesTask.js";
import { AddRelayPluginConfigurationTask } from "./tasks/AddRelayPluginConfigurationTask.js";
import { AddRelayEnvironmentTask } from "./tasks/AddRelayEnvironmentTask.js";
import { traverseUpToFindFile, getPackageManagerToUse } from "./helpers.js";
import { traverseUpToFindFile, hasUnsavedGitChanges, printError, } from "./helpers.js";
import { exit } from "process";
import { BABEL_RELAY_PACKAGE, PACKAGE_FILE, VITE_RELAY_PACKAGE, } from "./consts.js";
import { fileURLToPath } from "url";
import { getCliArguments } from "./cli.js";
const distDirectory = dirname(fileURLToPath(import.meta.url));
const ownPackageDirectory = path.join(distDirectory, "..");
const workingDirectory = process.cwd();
// FIND package.json FILE
const packageJsonFile = await traverseUpToFindFile(workingDirectory, "package.json");
const packageJsonFile = await traverseUpToFindFile(workingDirectory, PACKAGE_FILE);
if (!packageJsonFile) {
// package.json file is missing.
throw new Error("package.json file is missing");
printError(`Could not find a ${chalk.cyan.bold(PACKAGE_FILE)} in the ${chalk.cyan.bold(workingDirectory)} directory.`);
exit(1);
}
const projectRootDirectory = path.dirname(packageJsonFile);
// CHECK REPO FOR UNSAVED CHANGES
// const hasUnsavedChanges = await hasUnsavedGitChanges(projectDir);
// if (hasUnsavedChanges) {
// throw new Error("Project has unsaved changes");
// }
const settings = await readProjectSettings();
console.log();
const envArguments = {
workingDirectory,
ownPackageDirectory,
packageJsonFile,
projectRootDirectory,
};
// todo: handle errors
const cliArguments = await getCliArguments(envArguments);
const settings = Object.assign(Object.assign(Object.assign({}, envArguments), cliArguments), {
// todo: determine based on toolchain
srcDirectory: "./src" });
if (!settings.ignoreGitChanges) {
const hasUnsavedChanges = await hasUnsavedGitChanges(envArguments.projectRootDirectory);
if (hasUnsavedChanges) {
printError(`Please commit or discard all changes in the ${chalk.cyan.bold(envArguments.projectRootDirectory)} directory before continuing.`);
exit(1);
}
}
const dependencies = ["react-relay"];
const devDependencies = getRelayDevDependencies(settings.toolchain, settings.language);
const devDependencies = getRelayDevDependencies(settings.toolChain, settings.useTypescript);
const runner = new TaskRunner([

@@ -36,3 +50,3 @@ {

.join(" ")}`,
task: new InstallNpmPackagesTask(dependencies, settings.packageManager, projectRootDirectory),
task: new InstallNpmPackagesTask(dependencies, false, settings),
},

@@ -43,81 +57,48 @@ {

.join(" ")}`,
task: new InstallNpmPackagesTask(devDependencies, settings.packageManager, projectRootDirectory, true),
task: new InstallNpmPackagesTask(devDependencies, true, settings),
},
{
title: "Add Relay configuration to package.json",
task: new AddRelayConfigurationTask(packageJsonFile, settings.schemaFilePath, settings.language),
task: new AddRelayConfigurationTask(settings),
},
{
title: "Add Relay plugin configuration",
task: new AddRelayPluginConfigurationTask(projectRootDirectory, settings.toolchain, settings.language),
task: new AddRelayPluginConfigurationTask(settings),
},
{
title: "Add Relay environment",
task: new AddRelayEnvironmentTask(),
task: new AddRelayEnvironmentTask(settings),
},
{
title: `Generate GraphQL schema file (${chalk.cyan.bold(settings.schemaFilePath)})`,
task: new AddGraphQlSchemaFileTask(settings.schemaFilePath),
task: new AddGraphQlSchemaFileTask(settings),
},
]);
await runner.run();
try {
await runner.run();
}
catch (_a) {
console.log();
printError("Some of the tasks unexpectedly failed.");
exit(1);
}
console.log();
console.log(chalk.italic.bold("### NEXT STEPS ###"));
console.log(chalk.yellow.bold("Next steps:"));
console.log(`1. Replace ${chalk.cyan.bold(settings.schemaFilePath)} with your own GraphQL schema file.`);
console.log(`2. Replace the HOST variable in the RelayEnvironment.ts file.`);
// todo: get correct path to file
console.log(`2. Replace the value of the ${chalk.cyan.bold("HOST")} variable in the RelayEnvironment.ts file.`);
console.log();
// todo: add integration tests
async function readProjectSettings() {
const defaultPackageManager = getPackageManagerToUse();
// todo: handle artifact directory
// todo: handle error
return await inquirer.prompt([
{
name: "toolchain",
message: "Select the toolchain your project is using",
type: "list",
default: 0,
choices: ToolChainOptions,
},
{
name: "language",
message: "Select the language of your project",
type: "list",
default: 0,
choices: LanguageOptions,
},
{
// todo: validate that it's inside project dir and ends in .graphql
name: "schemaFilePath",
message: "Select the path to your GraphQL schema file",
type: "input",
default: "./src/schema.graphql",
validate: (input) => {
if (!input.endsWith(".graphql")) {
return `File needs to end in ${chalk.green(".graphql")}`;
}
return true;
},
},
{
name: "packageManager",
message: "Select the package manager you wish to use to install packages",
type: "list",
default: defaultPackageManager,
choices: PackageManagerOptions,
},
]);
}
export function getRelayDevDependencies(toolChain, language) {
let relayDevDep = ["relay-compiler"];
if (toolChain === "Create-React-App") {
relayDevDep = relayDevDep.concat(["babel-plugin-relay", "graphql"]);
function getRelayDevDependencies(toolChain, useTypescript) {
const relayDevDep = ["relay-compiler"];
if (useTypescript) {
relayDevDep.push("@types/react-relay");
relayDevDep.push("@types/relay-runtime");
}
else if (toolChain === "Vite") {
relayDevDep.push("vite-plugin-relay");
if (toolChain === "cra" || toolChain === "vite") {
relayDevDep.push(BABEL_RELAY_PACKAGE);
}
if (language === "Typescript") {
relayDevDep = relayDevDep.concat(["@types/react-relay"]);
if (toolChain === "vite") {
relayDevDep.push(VITE_RELAY_PACKAGE);
}
return relayDevDep;
}

@@ -1,4 +0,49 @@

import { exec, execSync } from "child_process";
import { exec, execSync, spawn } from "child_process";
import path from "path";
import { promises as fs } from "fs";
import fs from "fs/promises";
import { NEXTJS_CONFIG_FILE, TS_CONFIG_FILE, TYPESCRIPT_PACKAGE, } from "./consts.js";
import glob from "glob";
import t from "@babel/types";
import { parse } from "@babel/parser";
import generate from "@babel/generator";
import { format } from "prettier";
import chalk from "chalk";
export function printError(message) {
console.log(chalk.red("✖") + " " + message);
}
export function insertNamedImport(path, importName, packageName) {
const importIdentifier = t.identifier(importName);
const program = path.findParent((p) => p.isProgram());
const existingImport = program.node.body.find((s) => t.isImportDeclaration(s) &&
s.source.value === packageName &&
s.specifiers.some((sp) => t.isImportSpecifier(sp) && sp.local.name === importName));
if (!!existingImport) {
return importIdentifier;
}
const importDeclaration = t.importDeclaration([t.importSpecifier(t.cloneNode(importIdentifier), importIdentifier)], t.stringLiteral(packageName));
// Insert import at start of file.
program.node.body.unshift(importDeclaration);
return importIdentifier;
}
export function parseAst(code) {
return parse(code, {
sourceType: "module",
plugins: ["typescript", "jsx"],
});
}
export function printAst(ast, oldCode) {
const newCode = generate.default(ast, { retainLines: true }, oldCode).code;
return format(newCode, {
bracketSameLine: false,
parser: "babel-ts",
});
}
export function getRelayCompilerLanguage(useTypescript) {
if (useTypescript) {
return "typescript";
}
else {
return "javascript";
}
}
export async function hasUnsavedGitChanges(dir) {

@@ -20,5 +65,57 @@ const isPartOfGitRepo = await new Promise((resolve) => {

}
export function getPackageManagerToUse() {
export async function getProjectToolChain(projectRootDirectory) {
const nextjsConfigFile = await findFileInDirectory(projectRootDirectory, NEXTJS_CONFIG_FILE);
if (!!nextjsConfigFile) {
return "next";
}
const viteConfigFiles = await searchFilesInDirectory(projectRootDirectory, "vite.config.*");
if (viteConfigFiles.some((f) => !!f)) {
return "vite";
}
return "cra";
}
export async function doesProjectUseTypescript(projectRootDirectory, manager) {
const tsconfigFile = await findFileInDirectory(projectRootDirectory, TS_CONFIG_FILE);
if (!!tsconfigFile) {
return true;
}
const typescriptInstalled = await isNpmPackageInstalled(manager, projectRootDirectory, TYPESCRIPT_PACKAGE);
if (typescriptInstalled) {
return true;
}
return false;
}
export async function isNpmPackageInstalled(manager, projectRootDirectory, packageName) {
const command = manager;
const useYarn = manager === "yarn";
let args = [];
if (useYarn) {
args = ["list", "--depth=0", "--pattern", packageName];
}
else {
args = ["ls", "--depth=0", packageName];
}
return new Promise((resolve) => {
const child = spawn(command, args, {
// stdio: "inherit",
cwd: projectRootDirectory,
env: process.env,
shell: true,
});
child.stdout.on("data", (data) => {
const stringData = data.toString();
if (stringData.includes(packageName)) {
resolve(true);
}
});
child.on("close", () => {
resolve(false);
});
});
}
export async function getProjectPackageManager(projectRootDirectory) {
try {
const userAgent = process.env.npm_config_user_agent;
// If this script is being run by a specific manager,
// we use this mananger.
if (userAgent) {

@@ -34,12 +131,19 @@ if (userAgent.startsWith("yarn")) {

execSync("yarn --version", { stdio: "ignore" });
return "yarn";
const hasLockfile = await findFileInDirectory(projectRootDirectory, "yarn.lock");
if (hasLockfile) {
// Yarn is installed and the project contains a yarn.lock file.
return "yarn";
}
}
catch (_a) {
execSync("pnpm --version", { stdio: "ignore" });
return "pnpm";
const hasLockfile = await findFileInDirectory(projectRootDirectory, "pnpm-lock.yaml");
if (hasLockfile) {
// pnpm is installed and the project contains a pnpm-lock.yml file.
return "pnpm";
}
}
}
catch (_b) {
return "npm";
}
catch (_b) { }
return "npm";
}

@@ -77,1 +181,18 @@ export async function traverseUpToFindFile(directory, filename) {

}
export async function searchFilesInDirectory(directory, pattern) {
return new Promise((resolve) => {
try {
glob(pattern, { cwd: directory }, (error, matches) => {
if (error || !matches || !matches.some((m) => !!m)) {
resolve([]);
}
else {
resolve(matches);
}
});
}
catch (_a) {
resolve([]);
}
});
}

@@ -21,9 +21,12 @@ import ora from "ora";

let errorMsg;
if (!!error && typeof error === "string") {
errorMsg = error;
if (!!error) {
if (typeof error === "string") {
errorMsg = error;
}
else if (error instanceof Error) {
errorMsg = error.message;
}
}
errorMsg !== null && errorMsg !== void 0 ? errorMsg : (errorMsg = "Unexpected error");
task.error(errorMsg);
// throw error;
break;
}

@@ -30,0 +33,0 @@ }

@@ -1,2 +0,3 @@

import { existsSync, promises as fs } from "fs";
import { existsSync } from "fs";
import fs from "fs/promises";
import { EOL } from "os";

@@ -6,12 +7,12 @@ import { TaskBase } from "../TaskBase.js";

export class AddGraphQlSchemaFileTask extends TaskBase {
constructor(schemaFilePath) {
constructor(settings) {
super();
this.schemaFilePath = schemaFilePath;
this.settings = settings;
}
async run() {
if (existsSync(this.schemaFilePath)) {
if (existsSync(this.settings.schemaFilePath)) {
this.skip("File exists");
}
await fs.writeFile(this.schemaFilePath, schemaGraphQLContent, "utf-8");
await fs.writeFile(this.settings.schemaFilePath, schemaGraphQLContent, "utf-8");
}
}
import { TaskBase } from "../TaskBase.js";
import { promises as fs } from "fs";
import fs from "fs/promises";
import { getRelayCompilerLanguage } from "../helpers.js";
export class AddRelayConfigurationTask extends TaskBase {
constructor(packageJsonFile, schemaFilePath, language) {
constructor(settings) {
super();
this.packageJsonFile = packageJsonFile;
this.schemaFilePath = schemaFilePath;
this.language = language;
this.settings = settings;
}
async run() {
var _a;
const compilerLanguage = getCompilerLanguage(this.language);
// todo: handle error
const packageJsonContent = await fs.readFile(this.packageJsonFile, {
const packageJsonContent = await fs.readFile(this.settings.packageJsonFile, {
encoding: "utf-8",

@@ -27,6 +25,5 @@ });

packageJson["relay"] = {
// todo: this should probably be different for the Next.js project
src: "./src",
language: compilerLanguage,
schema: this.schemaFilePath,
src: this.settings.srcDirectory,
language: getRelayCompilerLanguage(this.settings.useTypescript),
schema: this.settings.schemaFilePath,
exclude: [

@@ -41,14 +38,4 @@ "**/node_modules/**",

// todo: handle error
await fs.writeFile(this.packageJsonFile, serializedPackageJson, "utf-8");
await fs.writeFile(this.settings.packageJsonFile, serializedPackageJson, "utf-8");
}
}
function getCompilerLanguage(language) {
switch (language) {
case "Typescript":
return "typescript";
case "Flow":
return "flow";
default:
return "javascript";
}
}

@@ -0,6 +1,77 @@

import traverse from "@babel/traverse";
import fs from "fs-extra";
import path from "path";
import { VITE_MAIN_FILE_NO_EXT, VITE_RELAY_ENV_FILE_NO_EXT, } from "../consts.js";
import { findFileInDirectory, insertNamedImport, parseAst, printAst, } from "../helpers.js";
import { TaskBase } from "../TaskBase.js";
import t from "@babel/types";
export class AddRelayEnvironmentTask extends TaskBase {
run() {
return Promise.resolve();
constructor(settings) {
super();
this.settings = settings;
}
async run() {
switch (this.settings.toolChain) {
case "vite":
await this.configureVite();
break;
// todo: implement CRA and Next.js
default:
throw new Error("Unsupported toolchain");
}
}
async configureVite() {
await this.addRelayEnvironmentFile(VITE_RELAY_ENV_FILE_NO_EXT);
const relativeMainFilepath = VITE_MAIN_FILE_NO_EXT + (this.settings.useTypescript ? ".tsx" : ".jsx");
const searchDirectory = path.dirname(path.join(this.settings.projectRootDirectory, relativeMainFilepath));
const mainFilename = path.basename(relativeMainFilepath);
const mainFilePath = await findFileInDirectory(searchDirectory, mainFilename);
if (!mainFilePath) {
throw new Error(`${relativeMainFilepath} not found`);
}
const mainCode = await fs.readFile(mainFilePath, "utf-8");
const ast = parseAst(mainCode);
const RELAY_ENV_PROVIDER = "RelayEnvironmentProvider";
traverse.default(ast, {
JSXElement: (path) => {
const parent = path.parentPath.node;
// Find ReactDOM.render(...)
if (!t.isCallExpression(parent) ||
!t.isMemberExpression(parent.callee) ||
!t.isIdentifier(parent.callee.property) ||
parent.callee.property.name !== "render") {
return;
}
const envId = insertNamedImport(path, "RelayEnvironment", "./RelayEnvironment");
const envProviderId = t.jsxIdentifier(insertNamedImport(path, RELAY_ENV_PROVIDER, "react-relay").name);
if (t.isJSXIdentifier(path.node.openingElement.name) &&
path.node.openingElement.name.name === envProviderId.name) {
// JSX has already been wrapped.
return;
}
const test = t.jsxExpressionContainer(envId);
// Wrap JSX inside render() into RelayEnvironmentProvider.
path.replaceWith(t.jsxElement(t.jsxOpeningElement(envProviderId, [
t.jsxAttribute(t.jsxIdentifier("environment"), test),
]), t.jsxClosingElement(envProviderId), [path.node]));
path.skip();
},
});
const updatedCode = printAst(ast, mainCode);
await fs.writeFile(mainFilePath, updatedCode, "utf-8");
}
async addRelayEnvironmentFile(filepathNoExt) {
const relativeRelayEnvFilepath = filepathNoExt + (this.settings.useTypescript ? ".ts" : ".js");
const relayEnvFilepath = path.join(this.settings.projectRootDirectory, relativeRelayEnvFilepath);
let srcFile;
if (this.settings.useTypescript) {
srcFile = "./assets/env_ts";
}
else {
srcFile = "./assets/env";
}
const srcFilepath = path.join(this.settings.ownPackageDirectory, srcFile);
// todo: handle error
await fs.copyFile(srcFilepath, relayEnvFilepath);
}
}

@@ -1,15 +0,20 @@

import { findFileInDirectory } from "../helpers.js";
import { findFileInDirectory, getRelayCompilerLanguage, parseAst, printAst, } from "../helpers.js";
import { TaskBase } from "../TaskBase.js";
import fs from "fs/promises";
import traverse from "@babel/traverse";
import t from "@babel/types";
import { NEXTJS_CONFIG_FILE, VITE_CONFIG_FILE_NO_EXT } from "../consts.js";
export class AddRelayPluginConfigurationTask extends TaskBase {
constructor(workingDirectory, toolChain, language) {
constructor(settings) {
super();
this.workingDirectory = workingDirectory;
this.toolChain = toolChain;
this.language = language;
this.settings = settings;
}
async run() {
switch (this.toolChain) {
case "Vite":
switch (this.settings.toolChain) {
case "vite":
await this.configureVite();
break;
case "next":
await this.configureNext();
break;
default:

@@ -19,10 +24,136 @@ throw new Error("Unsupported toolchain");

}
async configureNext() {
const configFilepath = await findFileInDirectory(this.settings.projectRootDirectory, NEXTJS_CONFIG_FILE);
if (!configFilepath) {
throw new Error(`${NEXTJS_CONFIG_FILE} not found`);
}
// todo: handle errors
const configCode = await fs.readFile(configFilepath, "utf-8");
const ast = parseAst(configCode);
traverse.default(ast, {
AssignmentExpression: (path) => {
const node = path.node;
// We are looking for module.exports = ???.
if (node.operator !== "=" ||
!t.isMemberExpression(node.left) ||
!t.isIdentifier(node.left.object) ||
!t.isIdentifier(node.left.property) ||
node.left.object.name !== "module" ||
node.left.property.name !== "exports") {
throw new Error(`Expected to find a module.exports assignment that exports the Next.js configuration from ${NEXTJS_CONFIG_FILE}.`);
}
let objExp;
// We are looking for the object expression
// that was assigned to module.exports.
if (t.isIdentifier(node.right)) {
// The export is linked to a variable,
// so we need to resolve the variable declaration.
const binding = path.scope.getBinding(node.right.name);
if (!binding ||
!t.isVariableDeclarator(binding.path.node) ||
!t.isObjectExpression(binding.path.node.init)) {
throw new Error(`module.exports in ${NEXTJS_CONFIG_FILE} references a variable, which is not a valid object definition.`);
}
objExp = binding.path.node.init;
}
else if (t.isObjectExpression(node.right)) {
objExp = node.right;
}
else {
throw new Error(`Expected to find a module.exports assignment that exports the Next.js configuration from ${NEXTJS_CONFIG_FILE}.`);
}
// We are creating or getting the 'compiler' property.
let compilerProperty = objExp.properties.find((p) => t.isObjectProperty(p) &&
t.isIdentifier(p.key) &&
p.key.name === "compiler");
if (!compilerProperty) {
compilerProperty = t.objectProperty(t.identifier("compiler"), t.objectExpression([]));
objExp.properties.push(compilerProperty);
}
if (!t.isObjectExpression(compilerProperty.value)) {
throw new Error(`Could not create or get a "compiler" property on the Next.js configuration object in ${NEXTJS_CONFIG_FILE}.`);
}
const relayProperty = compilerProperty.value.properties.find((p) => t.isObjectProperty(p) &&
t.isIdentifier(p.key) &&
p.key.name === "relay");
if (!!relayProperty) {
// A "relay" property already exists.
return;
}
// Add the "relay" property to the "compiler" property object.
compilerProperty.value.properties.push(t.objectProperty(t.identifier("relay"), t.objectExpression([
t.objectProperty(t.identifier("src"), t.stringLiteral(this.settings.srcDirectory)),
t.objectProperty(t.identifier("language"), t.stringLiteral(getRelayCompilerLanguage(this.settings.useTypescript))),
// todo: add artifact directory
])));
},
});
const updatedConfigCode = printAst(ast, configCode);
await fs.writeFile(configFilepath, updatedConfigCode, "utf-8");
}
async configureVite() {
const configFilename = "vite.config" + (this.language === "Typescript" ? ".ts" : ".js");
const configFilepath = await findFileInDirectory(this.workingDirectory, configFilename);
const relayImportName = "relay";
const configFilename = VITE_CONFIG_FILE_NO_EXT + (this.settings.useTypescript ? ".ts" : ".js");
const configFilepath = await findFileInDirectory(this.settings.projectRootDirectory, configFilename);
if (!configFilepath) {
throw new Error(`Could not find ${configFilename} in ${this.workingDirectory}`);
throw new Error(`${configFilename} not found`);
}
// todo: parse config and modify
// todo: handle errors
const configCode = await fs.readFile(configFilepath, "utf-8");
const ast = parseAst(configCode);
traverse.default(ast, {
Program: (path) => {
const hasRelayImport = path
.get("body")
.some((s) => s.isImportDeclaration() &&
s.node.specifiers.some((sp) => t.isImportDefaultSpecifier(sp) &&
sp.local.name === relayImportName));
if (hasRelayImport) {
// Import already exists.
return;
}
const importDeclaration = t.importDeclaration([t.importDefaultSpecifier(t.identifier(relayImportName))],
// todo: replace with VITE_RELAY_PACKAGE,
// once it no longer has the explict version
t.stringLiteral("vite-plugin-relay"));
// Insert import at start of file.
path.node.body.unshift(importDeclaration);
},
ExportDefaultDeclaration: (path) => {
const node = path.node;
// Find export default defineConfig(???)
if (!t.isCallExpression(node.declaration) ||
node.declaration.arguments.length < 1 ||
!t.isIdentifier(node.declaration.callee) ||
node.declaration.callee.name !== "defineConfig") {
throw new Error(`Expected a export default defineConfig({}) in ${configFilename}.`);
}
const arg = node.declaration.arguments[0];
if (!t.isObjectExpression(arg)) {
throw new Error(`Expected a export default defineConfig({}) in ${configFilename}.`);
}
// We are creating or getting the 'plugins' property.
let pluginsProperty = arg.properties.find((p) => t.isObjectProperty(p) &&
t.isIdentifier(p.key) &&
p.key.name === "plugins");
if (!pluginsProperty) {
pluginsProperty = t.objectProperty(t.identifier("plugins"), t.arrayExpression([]));
arg.properties.push(pluginsProperty);
}
if (!t.isArrayExpression(pluginsProperty.value)) {
throw new Error(`Could not create or get a "plugins" property on the Vite configuration object in ${configFilename}.`);
}
const vitePlugins = pluginsProperty.value.elements;
if (vitePlugins.some((p) => t.isIdentifier(p) && p.name === relayImportName)) {
// A "relay" entry already exists.
return;
}
const relayPlugin = t.identifier(relayImportName);
// Add the "relay" import to the "plugins".
vitePlugins.push(relayPlugin);
},
});
const updatedConfigCode = printAst(ast, configCode);
await fs.writeFile(configFilepath, updatedConfigCode, "utf-8");
}
}

@@ -0,16 +1,16 @@

import { spawn } from "child_process";
import { TaskBase } from "../TaskBase.js";
export class InstallNpmPackagesTask extends TaskBase {
constructor(packages, manager, workingDirectory, isDevDependency = false) {
constructor(packages, isDevDependency, settings) {
super();
this.packages = packages;
this.manager = manager;
this.workingDirectory = workingDirectory;
this.isDevDependency = isDevDependency;
this.settings = settings;
}
async run() {
const command = this.manager;
const useYarn = this.manager === "yarn";
const command = this.settings.packageManager;
const useYarn = command === "yarn";
let args = [];
if (useYarn) {
args = ["add", "--exact", "--cwd", this.workingDirectory];
args = ["add", "--exact", "--cwd", this.settings.projectRootDirectory];
if (this.isDevDependency) {

@@ -29,19 +29,18 @@ args.push("--dev");

}
return Promise.resolve();
// return new Promise((resolve, reject) => {
// const child = spawn(command, args, {
// // stdio: "inherit",
// cwd: this.workingDirectory,
// env: process.env,
// shell: true,
// });
// child.on("close", (code) => {
// if (code !== 0) {
// reject({ command: `${command} ${args.join(" ")}` });
// return;
// }
// resolve();
// });
// });
return new Promise((resolve, reject) => {
const child = spawn(command, args, {
// stdio: "inherit",
cwd: this.settings.projectRootDirectory,
env: process.env,
shell: true,
});
child.on("close", (code) => {
if (code !== 0) {
reject({ command: `${command} ${args.join(" ")}` });
return;
}
resolve();
});
});
}
}

@@ -1,7 +0,2 @@

export const ToolChainOptions = [
"Create-React-App",
"Next.js",
"Vite",
];
export const LanguageOptions = ["Typescript", "JavaScript", "Flow"];
export const ToolChainOptions = ["cra", "next", "vite"];
export const PackageManagerOptions = ["npm", "yarn", "pnpm"];
{
"name": "@tobiastengler/create-relay-app",
"version": "0.0.0-experimental-c4ec8b793",
"version": "0.0.0-experimental-e6e505b7a",
"description": "Easy configuration of Relay for existing projects",
"homepage": "https://github.com/tobias-tengler/create-relay-app#readme",
"license": "MIT",
"author": "tobias-tengler",
"author": {
"name": "Tobias Tengler",
"url": "https://github.com/tobias-tengler",
"email": "contact.tobiastengler@gmail.com"
},
"repository": {
"type": "git",
"url": "git+https://github.com/tobias-tengler/create-relay-app.git"
},
"bugs": {
"url": "https://github.com/tobias-tengler/create-relay-app/issues"
},
"keywords": [],
"files": [
"dist"
"./dist",
"./assets"
],

@@ -17,5 +32,11 @@ "bin": "./dist/bin.js",

"devDependencies": {
"@types/babel__generator": "^7.6.4",
"@types/babel__traverse": "^7.18.0",
"@types/fs-extra": "^9.0.13",
"@types/glob": "^7.2.0",
"@types/inquirer": "^9.0.0",
"@types/node": "^18.6.5",
"@types/ora": "^3.2.0",
"@types/prettier": "^2.7.0",
"fs-extra": "^10.1.0",
"tslib": "^2.4.0",

@@ -25,6 +46,12 @@ "typescript": "^4.7.4"

"dependencies": {
"@babel/generator": "^7.18.12",
"@babel/parser": "^7.18.11",
"@babel/traverse": "^7.18.11",
"chalk": "^5.0.1",
"commander": "^9.4.0",
"glob": "^8.0.3",
"inquirer": "^9.1.0",
"ora": "^6.1.2"
"ora": "^6.1.2",
"prettier": "^2.7.1"
}
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc