From 8e1cb8fb704c733a45659678400c57564ff48317 Mon Sep 17 00:00:00 2001 From: Marcus Schiesser <mail@marcusschiesser.de> Date: Wed, 25 Oct 2023 17:04:07 +0700 Subject: [PATCH] use prettier --- packages/create-llama/create-app.ts | 246 +++++++------- packages/create-llama/helpers/copy.ts | 42 +-- packages/create-llama/helpers/examples.ts | 112 ++++--- .../create-llama/helpers/get-pkg-manager.ts | 18 +- packages/create-llama/helpers/git.ts | 48 +-- packages/create-llama/helpers/install.ts | 38 +-- .../create-llama/helpers/is-folder-empty.ts | 76 ++--- packages/create-llama/helpers/is-online.ts | 34 +- packages/create-llama/helpers/is-writeable.ts | 8 +- packages/create-llama/helpers/make-dir.ts | 6 +- packages/create-llama/helpers/validate-pkg.ts | 12 +- packages/create-llama/index.ts | 316 +++++++++--------- packages/create-llama/templates/index.ts | 223 ++++++------ .../simple/nextjs/app/api/llm/route.ts | 80 ++--- .../nextjs/app/components/message-form.tsx | 74 ++-- .../templates/simple/nextjs/app/layout.tsx | 12 +- .../templates/simple/nextjs/app/page.tsx | 58 ++-- .../simple/nextjs/tailwind.config.ts | 18 +- packages/create-llama/templates/types.ts | 32 +- 19 files changed, 723 insertions(+), 730 deletions(-) diff --git a/packages/create-llama/create-app.ts b/packages/create-llama/create-app.ts index 64d916078..fb76bc8a4 100644 --- a/packages/create-llama/create-app.ts +++ b/packages/create-llama/create-app.ts @@ -1,26 +1,26 @@ /* eslint-disable import/no-extraneous-dependencies */ -import retry from 'async-retry' -import { red, green, cyan } from 'picocolors' -import fs from 'fs' -import path from 'path' -import type { RepoInfo } from './helpers/examples' +import retry from "async-retry"; +import fs from "fs"; +import path from "path"; +import { cyan, green, red } from "picocolors"; +import type { RepoInfo } from "./helpers/examples"; import { downloadAndExtractExample, downloadAndExtractRepo, - getRepoInfo, existsInRepo, + getRepoInfo, hasRepo, -} from './helpers/examples' -import { makeDir } from './helpers/make-dir' -import { tryGitInit } from './helpers/git' -import { install } from './helpers/install' -import { isFolderEmpty } from './helpers/is-folder-empty' -import { getOnline } from './helpers/is-online' -import { isWriteable } from './helpers/is-writeable' -import type { PackageManager } from './helpers/get-pkg-manager' +} from "./helpers/examples"; +import type { PackageManager } from "./helpers/get-pkg-manager"; +import { tryGitInit } from "./helpers/git"; +import { install } from "./helpers/install"; +import { isFolderEmpty } from "./helpers/is-folder-empty"; +import { getOnline } from "./helpers/is-online"; +import { isWriteable } from "./helpers/is-writeable"; +import { makeDir } from "./helpers/make-dir"; -import type { TemplateMode, TemplateType } from './templates' -import { getTemplateFile, installTemplate } from './templates' +import type { TemplateMode, TemplateType } from "./templates"; +import { getTemplateFile, installTemplate } from "./templates"; export class DownloadError extends Error {} @@ -34,110 +34,110 @@ export async function createApp({ srcDir, importAlias, }: { - appPath: string - packageManager: PackageManager - example?: string - examplePath?: string - tailwind: boolean - eslint: boolean - srcDir: boolean - importAlias: string + appPath: string; + packageManager: PackageManager; + example?: string; + examplePath?: string; + tailwind: boolean; + eslint: boolean; + srcDir: boolean; + importAlias: string; }): Promise<void> { - let repoInfo: RepoInfo | undefined - const mode: TemplateMode = 'nextjs'; - const template: TemplateType = 'simple'; + let repoInfo: RepoInfo | undefined; + const mode: TemplateMode = "nextjs"; + const template: TemplateType = "simple"; if (example) { - let repoUrl: URL | undefined + let repoUrl: URL | undefined; try { - repoUrl = new URL(example) + repoUrl = new URL(example); } catch (error: any) { - if (error.code !== 'ERR_INVALID_URL') { - console.error(error) - process.exit(1) + if (error.code !== "ERR_INVALID_URL") { + console.error(error); + process.exit(1); } } if (repoUrl) { - if (repoUrl.origin !== 'https://github.com') { + if (repoUrl.origin !== "https://github.com") { console.error( `Invalid URL: ${red( - `"${example}"` - )}. Only GitHub repositories are supported. Please use a GitHub URL and try again.` - ) - process.exit(1) + `"${example}"`, + )}. Only GitHub repositories are supported. Please use a GitHub URL and try again.`, + ); + process.exit(1); } - repoInfo = await getRepoInfo(repoUrl, examplePath) + repoInfo = await getRepoInfo(repoUrl, examplePath); if (!repoInfo) { console.error( `Found invalid GitHub URL: ${red( - `"${example}"` - )}. Please fix the URL and try again.` - ) - process.exit(1) + `"${example}"`, + )}. Please fix the URL and try again.`, + ); + process.exit(1); } - const found = await hasRepo(repoInfo) + const found = await hasRepo(repoInfo); if (!found) { console.error( `Could not locate the repository for ${red( - `"${example}"` - )}. Please check that the repository exists and try again.` - ) - process.exit(1) + `"${example}"`, + )}. Please check that the repository exists and try again.`, + ); + process.exit(1); } - } else if (example !== '__internal-testing-retry') { - const found = await existsInRepo(example) + } else if (example !== "__internal-testing-retry") { + const found = await existsInRepo(example); if (!found) { console.error( `Could not locate an example named ${red( - `"${example}"` + `"${example}"`, )}. It could be due to the following:\n`, `1. Your spelling of example ${red( - `"${example}"` + `"${example}"`, )} might be incorrect.\n`, - `2. You might not be connected to the internet or you are behind a proxy.` - ) - process.exit(1) + `2. You might not be connected to the internet or you are behind a proxy.`, + ); + process.exit(1); } } } - const root = path.resolve(appPath) + const root = path.resolve(appPath); if (!(await isWriteable(path.dirname(root)))) { console.error( - 'The application path is not writable, please check folder permissions and try again.' - ) + "The application path is not writable, please check folder permissions and try again.", + ); console.error( - 'It is likely you do not have write permissions for this folder.' - ) - process.exit(1) + "It is likely you do not have write permissions for this folder.", + ); + process.exit(1); } - const appName = path.basename(root) + const appName = path.basename(root); - await makeDir(root) + await makeDir(root); if (!isFolderEmpty(root, appName)) { - process.exit(1) + process.exit(1); } - const useYarn = packageManager === 'yarn' - const isOnline = !useYarn || (await getOnline()) - const originalDirectory = process.cwd() + const useYarn = packageManager === "yarn"; + const isOnline = !useYarn || (await getOnline()); + const originalDirectory = process.cwd(); - console.log(`Creating a new LlamaIndex app in ${green(root)}.`) - console.log() + console.log(`Creating a new LlamaIndex app in ${green(root)}.`); + console.log(); - process.chdir(root) + process.chdir(root); - const packageJsonPath = path.join(root, 'package.json') - let hasPackageJson = false + const packageJsonPath = path.join(root, "package.json"); + let hasPackageJson = false; if (example) { /** @@ -145,64 +145,64 @@ export async function createApp({ */ try { if (repoInfo) { - const repoInfo2 = repoInfo + const repoInfo2 = repoInfo; console.log( `Downloading files from repo ${cyan( - example - )}. This might take a moment.` - ) - console.log() + example, + )}. This might take a moment.`, + ); + console.log(); await retry(() => downloadAndExtractRepo(root, repoInfo2), { retries: 3, - }) + }); } else { console.log( `Downloading files for example ${cyan( - example - )}. This might take a moment.` - ) - console.log() + example, + )}. This might take a moment.`, + ); + console.log(); await retry(() => downloadAndExtractExample(root, example), { retries: 3, - }) + }); } } catch (reason) { function isErrorLike(err: unknown): err is { message: string } { return ( - typeof err === 'object' && + typeof err === "object" && err !== null && - typeof (err as { message?: unknown }).message === 'string' - ) + typeof (err as { message?: unknown }).message === "string" + ); } throw new DownloadError( - isErrorLike(reason) ? reason.message : reason + '' - ) + isErrorLike(reason) ? reason.message : reason + "", + ); } // Copy `.gitignore` if the application did not provide one - const ignorePath = path.join(root, '.gitignore') + const ignorePath = path.join(root, ".gitignore"); if (!fs.existsSync(ignorePath)) { fs.copyFileSync( - getTemplateFile({ template, mode, file: 'gitignore' }), - ignorePath - ) + getTemplateFile({ template, mode, file: "gitignore" }), + ignorePath, + ); } // Copy `next-env.d.ts` to any example that is typescript - const tsconfigPath = path.join(root, 'tsconfig.json') + const tsconfigPath = path.join(root, "tsconfig.json"); if (fs.existsSync(tsconfigPath)) { fs.copyFileSync( - getTemplateFile({ template, mode: 'nextjs', file: 'next-env.d.ts' }), - path.join(root, 'next-env.d.ts') - ) + getTemplateFile({ template, mode: "nextjs", file: "next-env.d.ts" }), + path.join(root, "next-env.d.ts"), + ); } - hasPackageJson = fs.existsSync(packageJsonPath) + hasPackageJson = fs.existsSync(packageJsonPath); if (hasPackageJson) { - console.log('Installing packages. This might take a couple of minutes.') - console.log() + console.log("Installing packages. This might take a couple of minutes."); + console.log(); - await install(packageManager, isOnline) - console.log() + await install(packageManager, isOnline); + console.log(); } } else { /** @@ -220,39 +220,39 @@ export async function createApp({ eslint, srcDir, importAlias, - }) + }); } if (tryGitInit(root)) { - console.log('Initialized a git repository.') - console.log() + console.log("Initialized a git repository."); + console.log(); } - let cdpath: string + let cdpath: string; if (path.join(originalDirectory, appName) === appPath) { - cdpath = appName + cdpath = appName; } else { - cdpath = appPath + cdpath = appPath; } - console.log(`${green('Success!')} Created ${appName} at ${appPath}`) + console.log(`${green("Success!")} Created ${appName} at ${appPath}`); if (hasPackageJson) { - console.log('Inside that directory, you can run several commands:') - console.log() - console.log(cyan(` ${packageManager} ${useYarn ? '' : 'run '}dev`)) - console.log(' Starts the development server.') - console.log() - console.log(cyan(` ${packageManager} ${useYarn ? '' : 'run '}build`)) - console.log(' Builds the app for production.') - console.log() - console.log(cyan(` ${packageManager} start`)) - console.log(' Runs the built app in production mode.') - console.log() - console.log('We suggest that you begin by typing:') - console.log() - console.log(cyan(' cd'), cdpath) - console.log(` ${cyan(`${packageManager} ${useYarn ? '' : 'run '}dev`)}`) + console.log("Inside that directory, you can run several commands:"); + console.log(); + console.log(cyan(` ${packageManager} ${useYarn ? "" : "run "}dev`)); + console.log(" Starts the development server."); + console.log(); + console.log(cyan(` ${packageManager} ${useYarn ? "" : "run "}build`)); + console.log(" Builds the app for production."); + console.log(); + console.log(cyan(` ${packageManager} start`)); + console.log(" Runs the built app in production mode."); + console.log(); + console.log("We suggest that you begin by typing:"); + console.log(); + console.log(cyan(" cd"), cdpath); + console.log(` ${cyan(`${packageManager} ${useYarn ? "" : "run "}dev`)}`); } - console.log() + console.log(); } diff --git a/packages/create-llama/helpers/copy.ts b/packages/create-llama/helpers/copy.ts index 407b000ab..a5b722ba3 100644 --- a/packages/create-llama/helpers/copy.ts +++ b/packages/create-llama/helpers/copy.ts @@ -1,25 +1,25 @@ /* eslint-disable import/no-extraneous-dependencies */ -import { async as glob } from 'fast-glob' -import path from 'path' -import fs from 'fs' +import { async as glob } from "fast-glob"; +import fs from "fs"; +import path from "path"; interface CopyOption { - cwd?: string - rename?: (basename: string) => string - parents?: boolean + cwd?: string; + rename?: (basename: string) => string; + parents?: boolean; } -const identity = (x: string) => x +const identity = (x: string) => x; export const copy = async ( src: string | string[], dest: string, - { cwd, rename = identity, parents = true }: CopyOption = {} + { cwd, rename = identity, parents = true }: CopyOption = {}, ) => { - const source = typeof src === 'string' ? [src] : src + const source = typeof src === "string" ? [src] : src; if (source.length === 0 || !dest) { - throw new TypeError('`src` and `dest` are required') + throw new TypeError("`src` and `dest` are required"); } const sourceFiles = await glob(source, { @@ -27,24 +27,24 @@ export const copy = async ( dot: true, absolute: false, stats: false, - }) + }); - const destRelativeToCwd = cwd ? path.resolve(cwd, dest) : dest + const destRelativeToCwd = cwd ? path.resolve(cwd, dest) : dest; return Promise.all( sourceFiles.map(async (p) => { - const dirname = path.dirname(p) - const basename = rename(path.basename(p)) + const dirname = path.dirname(p); + const basename = rename(path.basename(p)); - const from = cwd ? path.resolve(cwd, p) : p + const from = cwd ? path.resolve(cwd, p) : p; const to = parents ? path.join(destRelativeToCwd, dirname, basename) - : path.join(destRelativeToCwd, basename) + : path.join(destRelativeToCwd, basename); // Ensure the destination directory exists - await fs.promises.mkdir(path.dirname(to), { recursive: true }) + await fs.promises.mkdir(path.dirname(to), { recursive: true }); - return fs.promises.copyFile(from, to) - }) - ) -} + return fs.promises.copyFile(from, to); + }), + ); +}; diff --git a/packages/create-llama/helpers/examples.ts b/packages/create-llama/helpers/examples.ts index 97bbacf27..b8c74be6e 100644 --- a/packages/create-llama/helpers/examples.ts +++ b/packages/create-llama/helpers/examples.ts @@ -1,32 +1,34 @@ /* eslint-disable import/no-extraneous-dependencies */ -import got from 'got' -import tar from 'tar' -import { Stream } from 'stream' -import { promisify } from 'util' -import { join } from 'path' -import { tmpdir } from 'os' -import { createWriteStream, promises as fs } from 'fs' +import { createWriteStream, promises as fs } from "fs"; +import got from "got"; +import { tmpdir } from "os"; +import { join } from "path"; +import { Stream } from "stream"; +import tar from "tar"; +import { promisify } from "util"; -const pipeline = promisify(Stream.pipeline) +const pipeline = promisify(Stream.pipeline); export type RepoInfo = { - username: string - name: string - branch: string - filePath: string -} + username: string; + name: string; + branch: string; + filePath: string; +}; export async function isUrlOk(url: string): Promise<boolean> { - const res = await got.head(url).catch((e) => e) - return res.statusCode === 200 + const res = await got.head(url).catch((e) => e); + return res.statusCode === 200; } export async function getRepoInfo( url: URL, - examplePath?: string + examplePath?: string, ): Promise<RepoInfo | undefined> { - const [, username, name, t, _branch, ...file] = url.pathname.split('/') - const filePath = examplePath ? examplePath.replace(/^\//, '') : file.join('/') + const [, username, name, t, _branch, ...file] = url.pathname.split("/"); + const filePath = examplePath + ? examplePath.replace(/^\//, "") + : file.join("/"); if ( // Support repos whose entire purpose is to be a LlamaIndex example, e.g. @@ -35,25 +37,25 @@ export async function getRepoInfo( // Support GitHub URL that ends with a trailing slash, e.g. // https://github.com/:username/:my-cool-nextjs-example-repo-name/ // In this case "t" will be an empty string while the next part "_branch" will be undefined - (t === '' && _branch === undefined) + (t === "" && _branch === undefined) ) { const infoResponse = await got( - `https://api.github.com/repos/${username}/${name}` - ).catch((e) => e) + `https://api.github.com/repos/${username}/${name}`, + ).catch((e) => e); if (infoResponse.statusCode !== 200) { - return + return; } - const info = JSON.parse(infoResponse.body) - return { username, name, branch: info['default_branch'], filePath } + const info = JSON.parse(infoResponse.body); + return { username, name, branch: info["default_branch"], filePath }; } // If examplePath is available, the branch name takes the entire path const branch = examplePath - ? `${_branch}/${file.join('/')}`.replace(new RegExp(`/${filePath}|/$`), '') - : _branch + ? `${_branch}/${file.join("/")}`.replace(new RegExp(`/${filePath}|/$`), "") + : _branch; - if (username && name && branch && t === 'tree') { - return { username, name, branch, filePath } + if (username && name && branch && t === "tree") { + return { username, name, branch, filePath }; } } @@ -63,69 +65,69 @@ export function hasRepo({ branch, filePath, }: RepoInfo): Promise<boolean> { - const contentsUrl = `https://api.github.com/repos/${username}/${name}/contents` - const packagePath = `${filePath ? `/${filePath}` : ''}/package.json` + const contentsUrl = `https://api.github.com/repos/${username}/${name}/contents`; + const packagePath = `${filePath ? `/${filePath}` : ""}/package.json`; - return isUrlOk(contentsUrl + packagePath + `?ref=${branch}`) + return isUrlOk(contentsUrl + packagePath + `?ref=${branch}`); } export function existsInRepo(nameOrUrl: string): Promise<boolean> { try { - const url = new URL(nameOrUrl) - return isUrlOk(url.href) + const url = new URL(nameOrUrl); + return isUrlOk(url.href); } catch { return isUrlOk( `https://api.github.com/repos/vercel/next.js/contents/examples/${encodeURIComponent( - nameOrUrl - )}` - ) + nameOrUrl, + )}`, + ); } } async function downloadTar(url: string) { - const tempFile = join(tmpdir(), `next.js-cna-example.temp-${Date.now()}`) - await pipeline(got.stream(url), createWriteStream(tempFile)) - return tempFile + const tempFile = join(tmpdir(), `next.js-cna-example.temp-${Date.now()}`); + await pipeline(got.stream(url), createWriteStream(tempFile)); + return tempFile; } export async function downloadAndExtractRepo( root: string, - { username, name, branch, filePath }: RepoInfo + { username, name, branch, filePath }: RepoInfo, ) { const tempFile = await downloadTar( - `https://codeload.github.com/${username}/${name}/tar.gz/${branch}` - ) + `https://codeload.github.com/${username}/${name}/tar.gz/${branch}`, + ); await tar.x({ file: tempFile, cwd: root, - strip: filePath ? filePath.split('/').length + 1 : 1, + strip: filePath ? filePath.split("/").length + 1 : 1, filter: (p) => p.startsWith( - `${name}-${branch.replace(/\//g, '-')}${ - filePath ? `/${filePath}/` : '/' - }` + `${name}-${branch.replace(/\//g, "-")}${ + filePath ? `/${filePath}/` : "/" + }`, ), - }) + }); - await fs.unlink(tempFile) + await fs.unlink(tempFile); } export async function downloadAndExtractExample(root: string, name: string) { - if (name === '__internal-testing-retry') { - throw new Error('This is an internal example for testing the CLI.') + if (name === "__internal-testing-retry") { + throw new Error("This is an internal example for testing the CLI."); } const tempFile = await downloadTar( - 'https://codeload.github.com/vercel/next.js/tar.gz/canary' - ) + "https://codeload.github.com/vercel/next.js/tar.gz/canary", + ); await tar.x({ file: tempFile, cwd: root, - strip: 2 + name.split('/').length, + strip: 2 + name.split("/").length, filter: (p) => p.includes(`next.js-canary/examples/${name}/`), - }) + }); - await fs.unlink(tempFile) + await fs.unlink(tempFile); } diff --git a/packages/create-llama/helpers/get-pkg-manager.ts b/packages/create-llama/helpers/get-pkg-manager.ts index 20900ebcb..acc099f71 100644 --- a/packages/create-llama/helpers/get-pkg-manager.ts +++ b/packages/create-llama/helpers/get-pkg-manager.ts @@ -1,19 +1,19 @@ -export type PackageManager = 'npm' | 'pnpm' | 'yarn' | 'bun' +export type PackageManager = "npm" | "pnpm" | "yarn" | "bun"; export function getPkgManager(): PackageManager { - const userAgent = process.env.npm_config_user_agent || '' + const userAgent = process.env.npm_config_user_agent || ""; - if (userAgent.startsWith('yarn')) { - return 'yarn' + if (userAgent.startsWith("yarn")) { + return "yarn"; } - if (userAgent.startsWith('pnpm')) { - return 'pnpm' + if (userAgent.startsWith("pnpm")) { + return "pnpm"; } - if (userAgent.startsWith('bun')) { - return 'bun' + if (userAgent.startsWith("bun")) { + return "bun"; } - return 'npm' + return "npm"; } diff --git a/packages/create-llama/helpers/git.ts b/packages/create-llama/helpers/git.ts index 79eb9115a..fc27e6099 100644 --- a/packages/create-llama/helpers/git.ts +++ b/packages/create-llama/helpers/git.ts @@ -1,58 +1,58 @@ /* eslint-disable import/no-extraneous-dependencies */ -import { execSync } from 'child_process' -import path from 'path' -import fs from 'fs' +import { execSync } from "child_process"; +import fs from "fs"; +import path from "path"; function isInGitRepository(): boolean { try { - execSync('git rev-parse --is-inside-work-tree', { stdio: 'ignore' }) - return true + execSync("git rev-parse --is-inside-work-tree", { stdio: "ignore" }); + return true; } catch (_) {} - return false + return false; } function isInMercurialRepository(): boolean { try { - execSync('hg --cwd . root', { stdio: 'ignore' }) - return true + execSync("hg --cwd . root", { stdio: "ignore" }); + return true; } catch (_) {} - return false + return false; } function isDefaultBranchSet(): boolean { try { - execSync('git config init.defaultBranch', { stdio: 'ignore' }) - return true + execSync("git config init.defaultBranch", { stdio: "ignore" }); + return true; } catch (_) {} - return false + return false; } export function tryGitInit(root: string): boolean { - let didInit = false + let didInit = false; try { - execSync('git --version', { stdio: 'ignore' }) + execSync("git --version", { stdio: "ignore" }); if (isInGitRepository() || isInMercurialRepository()) { - return false + return false; } - execSync('git init', { stdio: 'ignore' }) - didInit = true + execSync("git init", { stdio: "ignore" }); + didInit = true; if (!isDefaultBranchSet()) { - execSync('git checkout -b main', { stdio: 'ignore' }) + execSync("git checkout -b main", { stdio: "ignore" }); } - execSync('git add -A', { stdio: 'ignore' }) + execSync("git add -A", { stdio: "ignore" }); execSync('git commit -m "Initial commit from Create Next App"', { - stdio: 'ignore', - }) - return true + stdio: "ignore", + }); + return true; } catch (e) { if (didInit) { try { - fs.rmSync(path.join(root, '.git'), { recursive: true, force: true }) + fs.rmSync(path.join(root, ".git"), { recursive: true, force: true }); } catch (_) {} } - return false + return false; } } diff --git a/packages/create-llama/helpers/install.ts b/packages/create-llama/helpers/install.ts index 911573b96..27d8f8132 100644 --- a/packages/create-llama/helpers/install.ts +++ b/packages/create-llama/helpers/install.ts @@ -1,7 +1,7 @@ /* eslint-disable import/no-extraneous-dependencies */ -import { yellow } from 'picocolors' -import spawn from 'cross-spawn' -import type { PackageManager } from './get-pkg-manager' +import spawn from "cross-spawn"; +import { yellow } from "picocolors"; +import type { PackageManager } from "./get-pkg-manager"; /** * Spawn a package manager installation based on user preference. @@ -12,14 +12,14 @@ export async function install( /** Indicate which package manager to use. */ packageManager: PackageManager, /** Indicate whether there is an active Internet connection.*/ - isOnline: boolean + isOnline: boolean, ): Promise<void> { - let args: string[] = ['install'] + let args: string[] = ["install"]; if (!isOnline) { console.log( - yellow('You appear to be offline.\nFalling back to the local cache.') - ) - args.push('--offline') + yellow("You appear to be offline.\nFalling back to the local cache."), + ); + args.push("--offline"); } /** * Return a Promise that resolves once the installation is finished. @@ -29,22 +29,22 @@ export async function install( * Spawn the installation process. */ const child = spawn(packageManager, args, { - stdio: 'inherit', + stdio: "inherit", env: { ...process.env, - ADBLOCK: '1', + ADBLOCK: "1", // we set NODE_ENV to development as pnpm skips dev // dependencies when production - NODE_ENV: 'development', - DISABLE_OPENCOLLECTIVE: '1', + NODE_ENV: "development", + DISABLE_OPENCOLLECTIVE: "1", }, - }) - child.on('close', (code) => { + }); + child.on("close", (code) => { if (code !== 0) { - reject({ command: `${packageManager} ${args.join(' ')}` }) - return + reject({ command: `${packageManager} ${args.join(" ")}` }); + return; } - resolve() - }) - }) + resolve(); + }); + }); } diff --git a/packages/create-llama/helpers/is-folder-empty.ts b/packages/create-llama/helpers/is-folder-empty.ts index ad89ec22f..927a344c0 100644 --- a/packages/create-llama/helpers/is-folder-empty.ts +++ b/packages/create-llama/helpers/is-folder-empty.ts @@ -1,62 +1,62 @@ /* eslint-disable import/no-extraneous-dependencies */ -import { green, blue } from 'picocolors' -import fs from 'fs' -import path from 'path' +import fs from "fs"; +import path from "path"; +import { blue, green } from "picocolors"; export function isFolderEmpty(root: string, name: string): boolean { const validFiles = [ - '.DS_Store', - '.git', - '.gitattributes', - '.gitignore', - '.gitlab-ci.yml', - '.hg', - '.hgcheck', - '.hgignore', - '.idea', - '.npmignore', - '.travis.yml', - 'LICENSE', - 'Thumbs.db', - 'docs', - 'mkdocs.yml', - 'npm-debug.log', - 'yarn-debug.log', - 'yarn-error.log', - 'yarnrc.yml', - '.yarn', - ] + ".DS_Store", + ".git", + ".gitattributes", + ".gitignore", + ".gitlab-ci.yml", + ".hg", + ".hgcheck", + ".hgignore", + ".idea", + ".npmignore", + ".travis.yml", + "LICENSE", + "Thumbs.db", + "docs", + "mkdocs.yml", + "npm-debug.log", + "yarn-debug.log", + "yarn-error.log", + "yarnrc.yml", + ".yarn", + ]; const conflicts = fs .readdirSync(root) .filter((file) => !validFiles.includes(file)) // Support IntelliJ IDEA-based editors - .filter((file) => !/\.iml$/.test(file)) + .filter((file) => !/\.iml$/.test(file)); if (conflicts.length > 0) { console.log( - `The directory ${green(name)} contains files that could conflict:` - ) - console.log() + `The directory ${green(name)} contains files that could conflict:`, + ); + console.log(); for (const file of conflicts) { try { - const stats = fs.lstatSync(path.join(root, file)) + const stats = fs.lstatSync(path.join(root, file)); if (stats.isDirectory()) { - console.log(` ${blue(file)}/`) + console.log(` ${blue(file)}/`); } else { - console.log(` ${file}`) + console.log(` ${file}`); } } catch { - console.log(` ${file}`) + console.log(` ${file}`); } } - console.log() + console.log(); console.log( - 'Either try using a new directory name, or remove the files listed above.' - ) - console.log() - return false + "Either try using a new directory name, or remove the files listed above.", + ); + console.log(); + return false; } - return true + return true; } diff --git a/packages/create-llama/helpers/is-online.ts b/packages/create-llama/helpers/is-online.ts index c2f3f83a9..eab698005 100644 --- a/packages/create-llama/helpers/is-online.ts +++ b/packages/create-llama/helpers/is-online.ts @@ -1,40 +1,40 @@ -import { execSync } from 'child_process' -import dns from 'dns' -import url from 'url' +import { execSync } from "child_process"; +import dns from "dns"; +import url from "url"; function getProxy(): string | undefined { if (process.env.https_proxy) { - return process.env.https_proxy + return process.env.https_proxy; } try { - const httpsProxy = execSync('npm config get https-proxy').toString().trim() - return httpsProxy !== 'null' ? httpsProxy : undefined + const httpsProxy = execSync("npm config get https-proxy").toString().trim(); + return httpsProxy !== "null" ? httpsProxy : undefined; } catch (e) { - return + return; } } export function getOnline(): Promise<boolean> { return new Promise((resolve) => { - dns.lookup('registry.yarnpkg.com', (registryErr) => { + dns.lookup("registry.yarnpkg.com", (registryErr) => { if (!registryErr) { - return resolve(true) + return resolve(true); } - const proxy = getProxy() + const proxy = getProxy(); if (!proxy) { - return resolve(false) + return resolve(false); } - const { hostname } = url.parse(proxy) + const { hostname } = url.parse(proxy); if (!hostname) { - return resolve(false) + return resolve(false); } dns.lookup(hostname, (proxyErr) => { - resolve(proxyErr == null) - }) - }) - }) + resolve(proxyErr == null); + }); + }); + }); } diff --git a/packages/create-llama/helpers/is-writeable.ts b/packages/create-llama/helpers/is-writeable.ts index 0b9e9abb4..fa29d6055 100644 --- a/packages/create-llama/helpers/is-writeable.ts +++ b/packages/create-llama/helpers/is-writeable.ts @@ -1,10 +1,10 @@ -import fs from 'fs' +import fs from "fs"; export async function isWriteable(directory: string): Promise<boolean> { try { - await fs.promises.access(directory, (fs.constants || fs).W_OK) - return true + await fs.promises.access(directory, (fs.constants || fs).W_OK); + return true; } catch (err) { - return false + return false; } } diff --git a/packages/create-llama/helpers/make-dir.ts b/packages/create-llama/helpers/make-dir.ts index 5b12b996f..2c258fd6b 100644 --- a/packages/create-llama/helpers/make-dir.ts +++ b/packages/create-llama/helpers/make-dir.ts @@ -1,8 +1,8 @@ -import fs from 'fs' +import fs from "fs"; export function makeDir( root: string, - options = { recursive: true } + options = { recursive: true }, ): Promise<string | undefined> { - return fs.promises.mkdir(root, options) + return fs.promises.mkdir(root, options); } diff --git a/packages/create-llama/helpers/validate-pkg.ts b/packages/create-llama/helpers/validate-pkg.ts index cff613818..68317653c 100644 --- a/packages/create-llama/helpers/validate-pkg.ts +++ b/packages/create-llama/helpers/validate-pkg.ts @@ -1,13 +1,13 @@ // eslint-disable-next-line import/no-extraneous-dependencies -import validateProjectName from 'validate-npm-package-name' +import validateProjectName from "validate-npm-package-name"; export function validateNpmName(name: string): { - valid: boolean - problems?: string[] + valid: boolean; + problems?: string[]; } { - const nameValidation = validateProjectName(name) + const nameValidation = validateProjectName(name); if (nameValidation.validForNewPackages) { - return { valid: true } + return { valid: true }; } return { @@ -16,5 +16,5 @@ export function validateNpmName(name: string): { ...(nameValidation.errors || []), ...(nameValidation.warnings || []), ], - } + }; } diff --git a/packages/create-llama/index.ts b/packages/create-llama/index.ts index 6c5bafeae..b74215f98 100644 --- a/packages/create-llama/index.ts +++ b/packages/create-llama/index.ts @@ -1,207 +1,207 @@ #!/usr/bin/env node /* eslint-disable import/no-extraneous-dependencies */ -import { cyan, green, red, yellow, bold, blue } from 'picocolors' -import Commander from 'commander' -import Conf from 'conf' -import path from 'path' -import prompts from 'prompts' -import checkForUpdate from 'update-check' -import { createApp, DownloadError } from './create-app' -import { getPkgManager } from './helpers/get-pkg-manager' -import { validateNpmName } from './helpers/validate-pkg' -import packageJson from './package.json' -import ciInfo from 'ci-info' -import { isFolderEmpty } from './helpers/is-folder-empty' -import fs from 'fs' - -let projectPath: string = '' - -const handleSigTerm = () => process.exit(0) - -process.on('SIGINT', handleSigTerm) -process.on('SIGTERM', handleSigTerm) +import ciInfo from "ci-info"; +import Commander from "commander"; +import Conf from "conf"; +import fs from "fs"; +import path from "path"; +import { blue, bold, cyan, green, red, yellow } from "picocolors"; +import prompts from "prompts"; +import checkForUpdate from "update-check"; +import { createApp, DownloadError } from "./create-app"; +import { getPkgManager } from "./helpers/get-pkg-manager"; +import { isFolderEmpty } from "./helpers/is-folder-empty"; +import { validateNpmName } from "./helpers/validate-pkg"; +import packageJson from "./package.json"; + +let projectPath: string = ""; + +const handleSigTerm = () => process.exit(0); + +process.on("SIGINT", handleSigTerm); +process.on("SIGTERM", handleSigTerm); const onPromptState = (state: any) => { if (state.aborted) { // If we don't re-enable the terminal cursor before exiting // the program, the cursor will remain hidden - process.stdout.write('\x1B[?25h') - process.stdout.write('\n') - process.exit(1) + process.stdout.write("\x1B[?25h"); + process.stdout.write("\n"); + process.exit(1); } -} +}; const program = new Commander.Command(packageJson.name) .version(packageJson.version) - .arguments('<project-directory>') - .usage(`${green('<project-directory>')} [options]`) + .arguments("<project-directory>") + .usage(`${green("<project-directory>")} [options]`) .action((name) => { - projectPath = name + projectPath = name; }) .option( - '--eslint', + "--eslint", ` Initialize with eslint config. -` +`, ) .option( - '--import-alias <alias-to-configure>', + "--import-alias <alias-to-configure>", ` Specify import alias to use (default "@/*"). -` +`, ) .option( - '--use-npm', + "--use-npm", ` Explicitly tell the CLI to bootstrap the application using npm -` +`, ) .option( - '--use-pnpm', + "--use-pnpm", ` Explicitly tell the CLI to bootstrap the application using pnpm -` +`, ) .option( - '--use-yarn', + "--use-yarn", ` Explicitly tell the CLI to bootstrap the application using Yarn -` +`, ) .option( - '--use-bun', + "--use-bun", ` Explicitly tell the CLI to bootstrap the application using Bun -` +`, ) .option( - '-e, --example [name]|[github-url]', + "-e, --example [name]|[github-url]", ` An example to bootstrap the app with. You can use an example name from the official LlamaIndex repo or a GitHub URL. The URL can use any branch and/or subdirectory -` +`, ) .option( - '--example-path <path-to-example>', + "--example-path <path-to-example>", ` In a rare case, your GitHub URL might contain a branch name with a slash (e.g. bug/fix-1) and the path to the example (e.g. foo/bar). In this case, you must specify the path to the example separately: --example-path foo/bar -` +`, ) .option( - '--reset-preferences', + "--reset-preferences", ` Explicitly tell the CLI to reset any stored preferences -` +`, ) .allowUnknownOption() - .parse(process.argv) + .parse(process.argv); const packageManager = !!program.useNpm - ? 'npm' + ? "npm" : !!program.usePnpm - ? 'pnpm' + ? "pnpm" : !!program.useYarn - ? 'yarn' + ? "yarn" : !!program.useBun - ? 'bun' - : getPkgManager() + ? "bun" + : getPkgManager(); async function run(): Promise<void> { - const conf = new Conf({ projectName: 'create-llama' }) + const conf = new Conf({ projectName: "create-llama" }); if (program.resetPreferences) { - conf.clear() - console.log(`Preferences reset successfully`) - return + conf.clear(); + console.log(`Preferences reset successfully`); + return; } - if (typeof projectPath === 'string') { - projectPath = projectPath.trim() + if (typeof projectPath === "string") { + projectPath = projectPath.trim(); } if (!projectPath) { const res = await prompts({ onState: onPromptState, - type: 'text', - name: 'path', - message: 'What is your project named?', - initial: 'my-app', + type: "text", + name: "path", + message: "What is your project named?", + initial: "my-app", validate: (name) => { - const validation = validateNpmName(path.basename(path.resolve(name))) + const validation = validateNpmName(path.basename(path.resolve(name))); if (validation.valid) { - return true + return true; } - return 'Invalid project name: ' + validation.problems![0] + return "Invalid project name: " + validation.problems![0]; }, - }) + }); - if (typeof res.path === 'string') { - projectPath = res.path.trim() + if (typeof res.path === "string") { + projectPath = res.path.trim(); } } if (!projectPath) { console.log( - '\nPlease specify the project directory:\n' + - ` ${cyan(program.name())} ${green('<project-directory>')}\n` + - 'For example:\n' + - ` ${cyan(program.name())} ${green('my-next-app')}\n\n` + - `Run ${cyan(`${program.name()} --help`)} to see all options.` - ) - process.exit(1) + "\nPlease specify the project directory:\n" + + ` ${cyan(program.name())} ${green("<project-directory>")}\n` + + "For example:\n" + + ` ${cyan(program.name())} ${green("my-next-app")}\n\n` + + `Run ${cyan(`${program.name()} --help`)} to see all options.`, + ); + process.exit(1); } - const resolvedProjectPath = path.resolve(projectPath) - const projectName = path.basename(resolvedProjectPath) + const resolvedProjectPath = path.resolve(projectPath); + const projectName = path.basename(resolvedProjectPath); - const { valid, problems } = validateNpmName(projectName) + const { valid, problems } = validateNpmName(projectName); if (!valid) { console.error( `Could not create a project called ${red( - `"${projectName}"` - )} because of npm naming restrictions:` - ) + `"${projectName}"`, + )} because of npm naming restrictions:`, + ); - problems!.forEach((p) => console.error(` ${red(bold('*'))} ${p}`)) - process.exit(1) + problems!.forEach((p) => console.error(` ${red(bold("*"))} ${p}`)); + process.exit(1); } if (program.example === true) { console.error( - 'Please provide an example name or url, otherwise remove the example option.' - ) - process.exit(1) + "Please provide an example name or url, otherwise remove the example option.", + ); + process.exit(1); } /** * Verify the project dir is empty or doesn't exist */ - const root = path.resolve(resolvedProjectPath) - const appName = path.basename(root) - const folderExists = fs.existsSync(root) + const root = path.resolve(resolvedProjectPath); + const appName = path.basename(root); + const folderExists = fs.existsSync(root); if (folderExists && !isFolderEmpty(root, appName)) { - process.exit(1) + process.exit(1); } - const example = typeof program.example === 'string' && program.example.trim() - const preferences = (conf.get('preferences') || {}) as Record< + const example = typeof program.example === "string" && program.example.trim(); + const preferences = (conf.get("preferences") || {}) as Record< string, boolean | string - > + >; /** * If the user does not provide the necessary flags, prompt them for whether * to use TS or JS. @@ -213,71 +213,71 @@ async function run(): Promise<void> { tailwind: true, app: true, srcDir: false, - importAlias: '@/*', + importAlias: "@/*", customizeImportAlias: false, - } + }; const getPrefOrDefault = (field: string) => - preferences[field] ?? defaults[field] + preferences[field] ?? defaults[field]; if ( - !process.argv.includes('--eslint') && - !process.argv.includes('--no-eslint') + !process.argv.includes("--eslint") && + !process.argv.includes("--no-eslint") ) { if (ciInfo.isCI) { - program.eslint = getPrefOrDefault('eslint') + program.eslint = getPrefOrDefault("eslint"); } else { - const styledEslint = blue('ESLint') + const styledEslint = blue("ESLint"); const { eslint } = await prompts({ onState: onPromptState, - type: 'toggle', - name: 'eslint', + type: "toggle", + name: "eslint", message: `Would you like to use ${styledEslint}?`, - initial: getPrefOrDefault('eslint'), - active: 'Yes', - inactive: 'No', - }) - program.eslint = Boolean(eslint) - preferences.eslint = Boolean(eslint) + initial: getPrefOrDefault("eslint"), + active: "Yes", + inactive: "No", + }); + program.eslint = Boolean(eslint); + preferences.eslint = Boolean(eslint); } } if ( - typeof program.importAlias !== 'string' || + typeof program.importAlias !== "string" || !program.importAlias.length ) { if (ciInfo.isCI) { // We don't use preferences here because the default value is @/* regardless of existing preferences - program.importAlias = defaults.importAlias + program.importAlias = defaults.importAlias; } else { - const styledImportAlias = blue('import alias') + const styledImportAlias = blue("import alias"); const { customizeImportAlias } = await prompts({ onState: onPromptState, - type: 'toggle', - name: 'customizeImportAlias', + type: "toggle", + name: "customizeImportAlias", message: `Would you like to customize the default ${styledImportAlias} (${defaults.importAlias})?`, - initial: getPrefOrDefault('customizeImportAlias'), - active: 'Yes', - inactive: 'No', - }) + initial: getPrefOrDefault("customizeImportAlias"), + active: "Yes", + inactive: "No", + }); if (!customizeImportAlias) { // We don't use preferences here because the default value is @/* regardless of existing preferences - program.importAlias = defaults.importAlias + program.importAlias = defaults.importAlias; } else { const { importAlias } = await prompts({ onState: onPromptState, - type: 'text', - name: 'importAlias', + type: "text", + name: "importAlias", message: `What ${styledImportAlias} would you like configured?`, - initial: getPrefOrDefault('importAlias'), + initial: getPrefOrDefault("importAlias"), validate: (value) => /.+\/\*/.test(value) ? true - : 'Import alias must follow the pattern <prefix>/*', - }) - program.importAlias = importAlias - preferences.importAlias = importAlias + : "Import alias must follow the pattern <prefix>/*", + }); + program.importAlias = importAlias; + preferences.importAlias = importAlias; } } } @@ -287,29 +287,29 @@ async function run(): Promise<void> { await createApp({ appPath: resolvedProjectPath, packageManager, - example: example && example !== 'default' ? example : undefined, + example: example && example !== "default" ? example : undefined, examplePath: program.examplePath, tailwind: true, eslint: program.eslint, srcDir: program.srcDir, importAlias: program.importAlias, - }) + }); } catch (reason) { if (!(reason instanceof DownloadError)) { - throw reason + throw reason; } const res = await prompts({ onState: onPromptState, - type: 'confirm', - name: 'builtin', + type: "confirm", + name: "builtin", message: `Could not download "${example}" because of a connectivity issue between your machine and GitHub.\n` + `Do you want to use the default template instead?`, initial: true, - }) + }); if (!res.builtin) { - throw reason + throw reason; } await createApp({ @@ -319,35 +319,35 @@ async function run(): Promise<void> { tailwind: true, srcDir: program.srcDir, importAlias: program.importAlias, - }) + }); } - conf.set('preferences', preferences) + conf.set("preferences", preferences); } -const update = checkForUpdate(packageJson).catch(() => null) +const update = checkForUpdate(packageJson).catch(() => null); async function notifyUpdate(): Promise<void> { try { - const res = await update + const res = await update; if (res?.latest) { const updateMessage = - packageManager === 'yarn' - ? 'yarn global add create-llama' - : packageManager === 'pnpm' - ? 'pnpm add -g create-llama' - : packageManager === 'bun' - ? 'bun add -g create-llama' - : 'npm i -g create-llama' + packageManager === "yarn" + ? "yarn global add create-llama" + : packageManager === "pnpm" + ? "pnpm add -g create-llama" + : packageManager === "bun" + ? "bun add -g create-llama" + : "npm i -g create-llama"; console.log( - yellow(bold('A new version of `create-llama` is available!')) + - '\n' + - 'You can update by running: ' + + yellow(bold("A new version of `create-llama` is available!")) + + "\n" + + "You can update by running: " + cyan(updateMessage) + - '\n' - ) + "\n", + ); } - process.exit() + process.exit(); } catch { // ignore error } @@ -356,19 +356,19 @@ async function notifyUpdate(): Promise<void> { run() .then(notifyUpdate) .catch(async (reason) => { - console.log() - console.log('Aborting installation.') + console.log(); + console.log("Aborting installation."); if (reason.command) { - console.log(` ${cyan(reason.command)} has failed.`) + console.log(` ${cyan(reason.command)} has failed.`); } else { console.log( - red('Unexpected error. Please report it as a bug:') + '\n', - reason - ) + red("Unexpected error. Please report it as a bug:") + "\n", + reason, + ); } - console.log() + console.log(); - await notifyUpdate() + await notifyUpdate(); - process.exit(1) - }) + process.exit(1); + }); diff --git a/packages/create-llama/templates/index.ts b/packages/create-llama/templates/index.ts index df407f7ac..e167f6450 100644 --- a/packages/create-llama/templates/index.ts +++ b/packages/create-llama/templates/index.ts @@ -1,17 +1,17 @@ -import { install } from '../helpers/install' -import { makeDir } from '../helpers/make-dir' -import { copy } from '../helpers/copy' +import { copy } from "../helpers/copy"; +import { install } from "../helpers/install"; +import { makeDir } from "../helpers/make-dir"; -import { async as glob } from 'fast-glob' -import os from 'os' -import fs from 'fs/promises' -import path from 'path' -import { cyan, bold } from 'picocolors' -import { Sema } from 'async-sema' +import { Sema } from "async-sema"; +import { async as glob } from "fast-glob"; +import fs from "fs/promises"; +import os from "os"; +import path from "path"; +import { bold, cyan } from "picocolors"; -import { GetTemplateFileArgs, InstallTemplateArgs } from './types' +import { GetTemplateFileArgs, InstallTemplateArgs } from "./types"; -const NEXT_VERSION = '13.5.6'; +const NEXT_VERSION = "13.5.6"; /** * Get the file path for a given file in a template, e.g. "next.config.js". @@ -21,10 +21,10 @@ export const getTemplateFile = ({ mode, file, }: GetTemplateFileArgs): string => { - return path.join(__dirname, template, mode, file) -} + return path.join(__dirname, template, mode, file); +}; -export const SRC_DIR_NAMES = ['app', 'pages', 'styles'] +export const SRC_DIR_NAMES = ["app", "pages", "styles"]; /** * Install a LlamaIndex internal template to a given `root` directory. @@ -41,208 +41,199 @@ export const installTemplate = async ({ srcDir, importAlias, }: InstallTemplateArgs) => { - console.log(bold(`Using ${packageManager}.`)) + console.log(bold(`Using ${packageManager}.`)); /** * Copy the template files to the target directory. */ - console.log('\nInitializing project with template:', template, '\n') - const templatePath = path.join(__dirname, template, mode) - const copySource = ['**'] - if (!eslint) copySource.push('!eslintrc.json') + console.log("\nInitializing project with template:", template, "\n"); + const templatePath = path.join(__dirname, template, mode); + const copySource = ["**"]; + if (!eslint) copySource.push("!eslintrc.json"); if (!tailwind) copySource.push( - mode == 'nextjs' ? 'tailwind.config.ts' : '!tailwind.config.js', - '!postcss.config.js' - ) + mode == "nextjs" ? "tailwind.config.ts" : "!tailwind.config.js", + "!postcss.config.js", + ); await copy(copySource, root, { parents: true, cwd: templatePath, rename(name) { switch (name) { - case 'gitignore': - case 'eslintrc.json': { - return `.${name}` + case "gitignore": + case "eslintrc.json": { + return `.${name}`; } // README.md is ignored by webpack-asset-relocator-loader used by ncc: // https://github.com/vercel/webpack-asset-relocator-loader/blob/e9308683d47ff507253e37c9bcbb99474603192b/src/asset-relocator.js#L227 - case 'README-template.md': { - return 'README.md' + case "README-template.md": { + return "README.md"; } default: { - return name + return name; } } }, - }) + }); - const tsconfigFile = path.join( - root, - 'tsconfig.json' - ) + const tsconfigFile = path.join(root, "tsconfig.json"); await fs.writeFile( tsconfigFile, - (await fs.readFile(tsconfigFile, 'utf8')) + (await fs.readFile(tsconfigFile, "utf8")) .replace( `"@/*": ["./*"]`, - srcDir ? `"@/*": ["./src/*"]` : `"@/*": ["./*"]` + srcDir ? `"@/*": ["./src/*"]` : `"@/*": ["./*"]`, ) - .replace(`"@/*":`, `"${importAlias}":`) - ) + .replace(`"@/*":`, `"${importAlias}":`), + ); // update import alias in any files if not using the default - if (importAlias !== '@/*') { - const files = await glob('**/*', { + if (importAlias !== "@/*") { + const files = await glob("**/*", { cwd: root, dot: true, stats: false, - }) - const writeSema = new Sema(8, { capacity: files.length }) + }); + const writeSema = new Sema(8, { capacity: files.length }); await Promise.all( files.map(async (file) => { // We don't want to modify compiler options in [ts/js]config.json - if (file === 'tsconfig.json' || file === 'jsconfig.json') return - await writeSema.acquire() - const filePath = path.join(root, file) + if (file === "tsconfig.json" || file === "jsconfig.json") return; + await writeSema.acquire(); + const filePath = path.join(root, file); if ((await fs.stat(filePath)).isFile()) { await fs.writeFile( filePath, - ( - await fs.readFile(filePath, 'utf8') - ).replace(`@/`, `${importAlias.replace(/\*/g, '')}`) - ) + (await fs.readFile(filePath, "utf8")).replace( + `@/`, + `${importAlias.replace(/\*/g, "")}`, + ), + ); } - await writeSema.release() - }) - ) + await writeSema.release(); + }), + ); } if (srcDir) { - await makeDir(path.join(root, 'src')) + await makeDir(path.join(root, "src")); await Promise.all( SRC_DIR_NAMES.map(async (file) => { await fs - .rename(path.join(root, file), path.join(root, 'src', file)) + .rename(path.join(root, file), path.join(root, "src", file)) .catch((err) => { - if (err.code !== 'ENOENT') { - throw err + if (err.code !== "ENOENT") { + throw err; } - }) - }) - ) + }); + }), + ); - const isAppTemplate = template.startsWith('app') + const isAppTemplate = template.startsWith("app"); // Change the `Get started by editing pages/index` / `app/page` to include `src` const indexPageFile = path.join( - 'src', - isAppTemplate ? 'app' : 'pages', - `${isAppTemplate ? 'page' : 'index'}.tsx` - ) + "src", + isAppTemplate ? "app" : "pages", + `${isAppTemplate ? "page" : "index"}.tsx`, + ); await fs.writeFile( indexPageFile, - ( - await fs.readFile(indexPageFile, 'utf8') - ).replace( - isAppTemplate ? 'app/page' : 'pages/index', - isAppTemplate ? 'src/app/page' : 'src/pages/index' - ) - ) + (await fs.readFile(indexPageFile, "utf8")).replace( + isAppTemplate ? "app/page" : "pages/index", + isAppTemplate ? "src/app/page" : "src/pages/index", + ), + ); if (tailwind) { - const tailwindConfigFile = path.join( - root, - 'tailwind.config.ts' - ) + const tailwindConfigFile = path.join(root, "tailwind.config.ts"); await fs.writeFile( tailwindConfigFile, - ( - await fs.readFile(tailwindConfigFile, 'utf8') - ).replace( + (await fs.readFile(tailwindConfigFile, "utf8")).replace( /\.\/(\w+)\/\*\*\/\*\.\{js,ts,jsx,tsx,mdx\}/g, - './src/$1/**/*.{js,ts,jsx,tsx,mdx}' - ) - ) + "./src/$1/**/*.{js,ts,jsx,tsx,mdx}", + ), + ); } } /** Create a package.json for the new project and write it to disk. */ const packageJson: any = { name: appName, - version: '0.1.0', + version: "0.1.0", private: true, scripts: { - dev: 'next dev', - build: 'next build', - start: 'next start', - lint: 'next lint', + dev: "next dev", + build: "next build", + start: "next start", + lint: "next lint", }, /** * Default dependencies. */ dependencies: { - react: '^18', - 'react-dom': '^18', + react: "^18", + "react-dom": "^18", next: NEXT_VERSION, llamaindex: "0.0.0-20231018030303", - encoding: "^0.1.13" + encoding: "^0.1.13", }, devDependencies: {}, - } + }; /** * TypeScript projects will have type definitions and other devDependencies. */ - packageJson.devDependencies = { - ...packageJson.devDependencies, - typescript: '^5', - '@types/node': '^20', - '@types/react': '^18', - '@types/react-dom': '^18', - } + packageJson.devDependencies = { + ...packageJson.devDependencies, + typescript: "^5", + "@types/node": "^20", + "@types/react": "^18", + "@types/react-dom": "^18", + }; /* Add Tailwind CSS dependencies. */ if (tailwind) { packageJson.devDependencies = { ...packageJson.devDependencies, - autoprefixer: '^10', - postcss: '^8', - tailwindcss: '^3', - } + autoprefixer: "^10", + postcss: "^8", + tailwindcss: "^3", + }; } /* Default ESLint dependencies. */ if (eslint) { packageJson.devDependencies = { ...packageJson.devDependencies, - eslint: '^8', - 'eslint-config-next': NEXT_VERSION, - } + eslint: "^8", + "eslint-config-next": NEXT_VERSION, + }; } - const devDeps = Object.keys(packageJson.devDependencies).length - if (!devDeps) delete packageJson.devDependencies + const devDeps = Object.keys(packageJson.devDependencies).length; + if (!devDeps) delete packageJson.devDependencies; await fs.writeFile( - path.join(root, 'package.json'), - JSON.stringify(packageJson, null, 2) + os.EOL - ) + path.join(root, "package.json"), + JSON.stringify(packageJson, null, 2) + os.EOL, + ); - console.log('\nInstalling dependencies:') + console.log("\nInstalling dependencies:"); for (const dependency in packageJson.dependencies) - console.log(`- ${cyan(dependency)}`) + console.log(`- ${cyan(dependency)}`); if (devDeps) { - console.log('\nInstalling devDependencies:') + console.log("\nInstalling devDependencies:"); for (const dependency in packageJson.devDependencies) - console.log(`- ${cyan(dependency)}`) + console.log(`- ${cyan(dependency)}`); } - console.log() + console.log(); - await install(packageManager, isOnline) -} + await install(packageManager, isOnline); +}; -export * from './types' +export * from "./types"; diff --git a/packages/create-llama/templates/simple/nextjs/app/api/llm/route.ts b/packages/create-llama/templates/simple/nextjs/app/api/llm/route.ts index bb3a11319..b399143b7 100644 --- a/packages/create-llama/templates/simple/nextjs/app/api/llm/route.ts +++ b/packages/create-llama/templates/simple/nextjs/app/api/llm/route.ts @@ -5,48 +5,48 @@ export const runtime = "nodejs"; export const dynamic = "force-dynamic"; export async function POST(request: NextRequest) { - try { - const body = await request.json(); - const { - message, - chatHistory, - }: { - message: string; - chatHistory: ChatMessage[]; - } = body; - if (!message || !chatHistory) { - return NextResponse.json( - { - error: "message, chatHistory are required in the request body", - }, - { status: 400 } - ); - } + try { + const body = await request.json(); + const { + message, + chatHistory, + }: { + message: string; + chatHistory: ChatMessage[]; + } = body; + if (!message || !chatHistory) { + return NextResponse.json( + { + error: "message, chatHistory are required in the request body", + }, + { status: 400 }, + ); + } - const llm = new OpenAI({ - model: "gpt-3.5-turbo", - }); + const llm = new OpenAI({ + model: "gpt-3.5-turbo", + }); - const chatEngine = new SimpleChatEngine({ - llm, - }); + const chatEngine = new SimpleChatEngine({ + llm, + }); - const response = await chatEngine.chat(message, chatHistory); - const result: ChatMessage = { - role: "assistant", - content: response.response, - }; + const response = await chatEngine.chat(message, chatHistory); + const result: ChatMessage = { + role: "assistant", + content: response.response, + }; - return NextResponse.json({ result }); - } catch (error) { - console.error("[LlamaIndex]", error); - return NextResponse.json( - { - error: (error as Error).message, - }, - { - status: 500, - } - ); - } + return NextResponse.json({ result }); + } catch (error) { + console.error("[LlamaIndex]", error); + return NextResponse.json( + { + error: (error as Error).message, + }, + { + status: 500, + }, + ); + } } diff --git a/packages/create-llama/templates/simple/nextjs/app/components/message-form.tsx b/packages/create-llama/templates/simple/nextjs/app/components/message-form.tsx index 0f67f43d3..59f42ce3a 100644 --- a/packages/create-llama/templates/simple/nextjs/app/components/message-form.tsx +++ b/packages/create-llama/templates/simple/nextjs/app/components/message-form.tsx @@ -2,42 +2,42 @@ import { ChatMessage } from "llamaindex"; export default function MessageForm() { - const testSendMessage = async (message: string) => { - const chatHistory: ChatMessage[] = []; - const apiRoute = "/api/llm"; - const response = await fetch(apiRoute, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ message, chatHistory }), - }); - const data = await response.json(); - alert(JSON.stringify(data)); - }; + const testSendMessage = async (message: string) => { + const chatHistory: ChatMessage[] = []; + const apiRoute = "/api/llm"; + const response = await fetch(apiRoute, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ message, chatHistory }), + }); + const data = await response.json(); + alert(JSON.stringify(data)); + }; - return ( - <form - onSubmit={(e) => { - e.preventDefault(); - const message = e.currentTarget.message.value; - testSendMessage(message); - }} - className="flex flex-col items-center justify-center w-full max-w-5xl p-4 space-y-4 bg-white rounded-xl shadow-xl" - > - <input - autoFocus - type="text" - name="message" - placeholder="Type a message" - className="w-full p-4 rounded-xl shadow-inner" - /> - <button - type="submit" - className="p-4 text-white rounded-xl shadow-xl bg-gradient-to-r from-cyan-500 to-sky-500 dark:from-cyan-600 dark:to-sky-600" - > - Send message - </button> - </form> - ); + return ( + <form + onSubmit={(e) => { + e.preventDefault(); + const message = e.currentTarget.message.value; + testSendMessage(message); + }} + className="flex flex-col items-center justify-center w-full max-w-5xl p-4 space-y-4 bg-white rounded-xl shadow-xl" + > + <input + autoFocus + type="text" + name="message" + placeholder="Type a message" + className="w-full p-4 rounded-xl shadow-inner" + /> + <button + type="submit" + className="p-4 text-white rounded-xl shadow-xl bg-gradient-to-r from-cyan-500 to-sky-500 dark:from-cyan-600 dark:to-sky-600" + > + Send message + </button> + </form> + ); } diff --git a/packages/create-llama/templates/simple/nextjs/app/layout.tsx b/packages/create-llama/templates/simple/nextjs/app/layout.tsx index 444a7b6ee..fb0977062 100644 --- a/packages/create-llama/templates/simple/nextjs/app/layout.tsx +++ b/packages/create-llama/templates/simple/nextjs/app/layout.tsx @@ -1,8 +1,8 @@ -import type { Metadata } from 'next' -import { Inter } from 'next/font/google' -import './globals.css' +import type { Metadata } from "next"; +import { Inter } from "next/font/google"; +import "./globals.css"; -const inter = Inter({ subsets: ['latin'] }) +const inter = Inter({ subsets: ["latin"] }); export const metadata: Metadata = { title: "Create Llama App", @@ -12,11 +12,11 @@ export const metadata: Metadata = { export default function RootLayout({ children, }: { - children: React.ReactNode + children: React.ReactNode; }) { return ( <html lang="en"> <body className={inter.className}>{children}</body> </html> - ) + ); } diff --git a/packages/create-llama/templates/simple/nextjs/app/page.tsx b/packages/create-llama/templates/simple/nextjs/app/page.tsx index 1a73edb1e..a6c7e79f0 100644 --- a/packages/create-llama/templates/simple/nextjs/app/page.tsx +++ b/packages/create-llama/templates/simple/nextjs/app/page.tsx @@ -2,33 +2,33 @@ import MessageForm from "@/app/components/message-form"; import Image from "next/image"; export default function Home() { - return ( - <main className="flex min-h-screen flex-col items-center gap-10 p-24"> - <div className="z-10 max-w-5xl w-full items-center justify-between font-mono text-sm lg:flex"> - <p className="fixed left-0 top-0 flex w-full justify-center border-b border-gray-300 bg-gradient-to-b from-zinc-200 pb-6 pt-8 backdrop-blur-2xl dark:border-neutral-800 dark:bg-zinc-800/30 dark:from-inherit lg:static lg:w-auto lg:rounded-xl lg:border lg:bg-gray-200 lg:p-4 lg:dark:bg-zinc-800/30"> - Get started by editing - <code className="font-mono font-bold">app/page.tsx</code> - </p> - <div className="fixed bottom-0 left-0 flex h-48 w-full items-end justify-center bg-gradient-to-t from-white via-white dark:from-black dark:via-black lg:static lg:h-auto lg:w-auto lg:bg-none"> - <a - className="pointer-events-none flex place-items-center gap-2 p-8 lg:pointer-events-auto lg:p-0" - href="https://vercel.com?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app" - target="_blank" - rel="noopener noreferrer" - > - By{" "} - <Image - src="/vercel.svg" - alt="Vercel Logo" - className="dark:invert" - width={100} - height={24} - priority - /> - </a> - </div> - </div> - <MessageForm /> - </main> - ); + return ( + <main className="flex min-h-screen flex-col items-center gap-10 p-24"> + <div className="z-10 max-w-5xl w-full items-center justify-between font-mono text-sm lg:flex"> + <p className="fixed left-0 top-0 flex w-full justify-center border-b border-gray-300 bg-gradient-to-b from-zinc-200 pb-6 pt-8 backdrop-blur-2xl dark:border-neutral-800 dark:bg-zinc-800/30 dark:from-inherit lg:static lg:w-auto lg:rounded-xl lg:border lg:bg-gray-200 lg:p-4 lg:dark:bg-zinc-800/30"> + Get started by editing + <code className="font-mono font-bold">app/page.tsx</code> + </p> + <div className="fixed bottom-0 left-0 flex h-48 w-full items-end justify-center bg-gradient-to-t from-white via-white dark:from-black dark:via-black lg:static lg:h-auto lg:w-auto lg:bg-none"> + <a + className="pointer-events-none flex place-items-center gap-2 p-8 lg:pointer-events-auto lg:p-0" + href="https://vercel.com?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app" + target="_blank" + rel="noopener noreferrer" + > + By{" "} + <Image + src="/vercel.svg" + alt="Vercel Logo" + className="dark:invert" + width={100} + height={24} + priority + /> + </a> + </div> + </div> + <MessageForm /> + </main> + ); } diff --git a/packages/create-llama/templates/simple/nextjs/tailwind.config.ts b/packages/create-llama/templates/simple/nextjs/tailwind.config.ts index c7ead8046..7e4bd91a0 100644 --- a/packages/create-llama/templates/simple/nextjs/tailwind.config.ts +++ b/packages/create-llama/templates/simple/nextjs/tailwind.config.ts @@ -1,20 +1,20 @@ -import type { Config } from 'tailwindcss' +import type { Config } from "tailwindcss"; const config: Config = { content: [ - './pages/**/*.{js,ts,jsx,tsx,mdx}', - './components/**/*.{js,ts,jsx,tsx,mdx}', - './app/**/*.{js,ts,jsx,tsx,mdx}', + "./pages/**/*.{js,ts,jsx,tsx,mdx}", + "./components/**/*.{js,ts,jsx,tsx,mdx}", + "./app/**/*.{js,ts,jsx,tsx,mdx}", ], theme: { extend: { backgroundImage: { - 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))', - 'gradient-conic': - 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))', + "gradient-radial": "radial-gradient(var(--tw-gradient-stops))", + "gradient-conic": + "conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))", }, }, }, plugins: [], -} -export default config +}; +export default config; diff --git a/packages/create-llama/templates/types.ts b/packages/create-llama/templates/types.ts index 541fa3d31..5312d80dd 100644 --- a/packages/create-llama/templates/types.ts +++ b/packages/create-llama/templates/types.ts @@ -1,24 +1,24 @@ -import { PackageManager } from '../helpers/get-pkg-manager' +import { PackageManager } from "../helpers/get-pkg-manager"; -export type TemplateType = 'simple' -export type TemplateMode = 'nextjs' +export type TemplateType = "simple"; +export type TemplateMode = "nextjs"; export interface GetTemplateFileArgs { - template: TemplateType - mode: TemplateMode - file: string + template: TemplateType; + mode: TemplateMode; + file: string; } export interface InstallTemplateArgs { - appName: string - root: string - packageManager: PackageManager - isOnline: boolean + appName: string; + root: string; + packageManager: PackageManager; + isOnline: boolean; - template: TemplateType - mode: TemplateMode - eslint: boolean - tailwind: boolean - srcDir: boolean - importAlias: string + template: TemplateType; + mode: TemplateMode; + eslint: boolean; + tailwind: boolean; + srcDir: boolean; + importAlias: string; } -- GitLab