diff --git a/packages/build-info/assets/logos/cedarjs/default.png b/packages/build-info/assets/logos/cedarjs/default.png new file mode 100644 index 0000000000..065039f937 Binary files /dev/null and b/packages/build-info/assets/logos/cedarjs/default.png differ diff --git a/packages/build-info/src/frameworks/cedar.test.ts b/packages/build-info/src/frameworks/cedar.test.ts new file mode 100644 index 0000000000..362ac12279 --- /dev/null +++ b/packages/build-info/src/frameworks/cedar.test.ts @@ -0,0 +1,100 @@ +import { beforeEach, expect, test } from 'vitest' + +import { mockFileSystem } from '../../tests/mock-file-system.js' +import { NodeFS } from '../node/file-system.js' +import { Project } from '../project.js' + +beforeEach((ctx) => { + ctx.fs = new NodeFS() +}) + +const cedarToml = ` +# This file contains the configuration settings for your Cedar app. +# This file is also what makes your Cedar app a Cedar app. +# If you remove it and try to run \`yarn cedar dev\`, you'll get an error. +# +# For the full list of options, see the "App Configuration: cedar.toml" doc: +# https://cedarjs.com/docs/app-configuration-cedar-toml + +[web] + title = "Cedar App" + port = 8910 + apiUrl = "/.redwood/functions" + includeEnvironmentVariables = [ + # Add any ENV vars that should be available to the web side to this array + # See https://cedarjs.com/docs/environment-variables#web + ] +[api] + port = 8911 +[browser] + open = true +[notifications] + versionUpdates = ["latest"] +` + +test('should detect cedar', async ({ fs }) => { + const cwd = mockFileSystem({ + 'cedar.toml': cedarToml, + 'package.json': JSON.stringify({ + private: true, + workspaces: { + packages: ['api', 'web'], + }, + devDependencies: { + '@cedarjs/core': '2.8.0', + }, + eslintConfig: { + extends: '@cedarjs/eslint-config', + root: true, + }, + engines: { + node: '=24.x', + }, + packageManager: 'yarn@4.12.0', + }), + 'web/package.json': JSON.stringify({ + name: 'web', + version: '0.0.0', + private: true, + browserslist: { + development: ['last 1 version'], + production: ['defaults'], + }, + dependencies: { + '@cedarjs/forms': '2.8.0', + '@cedarjs/router': '2.8.0', + '@cedarjs/web': '2.8.0', + react: '18.3.1', + 'react-dom': '18.3.1', + }, + devDependencies: { + '@cedarjs/vite': '2.8.0', + '@types/react': '^18.2.55', + '@types/react-dom': '^18.2.19', + }, + }), + 'api/package.json': JSON.stringify({ + name: 'api', + version: '0.0.0', + private: true, + dependencies: { + '@cedarjs/api': '2.8.0', + '@cedarjs/graphql-server': '2.8.0', + }, + }), + }) + + const project = new Project(fs, cwd, cwd) + + expect(await project.detectWorkspaces()).toBeNull() + const detected = await project.detectFrameworks() + + expect(detected).toHaveLength(1) + expect(detected?.[0].id).toBe('cedarjs') + expect(detected?.[0].name).toBe('CedarJS') + expect(detected?.[0].build.command).toBe('cedar deploy netlify') + expect(detected?.[0].build.directory).toBe('web/dist') + expect(detected?.[0].dev?.command).toBe('yarn cedar dev') + expect(detected?.[0].env.NODE_VERSION).toBe('24') + expect(detected?.[0].env.AWS_LAMBDA_JS_RUNTIME).toBe('nodejs24.x') +}) diff --git a/packages/build-info/src/frameworks/cedarjs.ts b/packages/build-info/src/frameworks/cedarjs.ts new file mode 100644 index 0000000000..a056682622 --- /dev/null +++ b/packages/build-info/src/frameworks/cedarjs.ts @@ -0,0 +1,35 @@ +import { BaseFramework, Category, Framework } from './framework.js' + +export class CedarJS extends BaseFramework implements Framework { + readonly id = 'cedarjs' + name = 'CedarJS' + npmDependencies = ['@cedarjs/core'] + configFiles = ['cedar.toml'] + category = Category.SSG + staticAssetsDirectory = 'public' + + dev = { + // Cedar only works with yarn + // https://cedarjs.com/docs/tutorial/chapter1/prerequisites#nodejs-and-yarn-versions + command: 'yarn cedar dev', + port: 8910, + pollingStrategies: [{ name: 'TCP' }], + } + + build = { + // explicitly not invoked with yarn: https://github.com/netlify/framework-info/commit/b3cd21d1e60d91facd397068f35b850b80d1ef13 + command: 'cedar deploy netlify', + directory: 'web/dist', + } + + env = { + AWS_LAMBDA_JS_RUNTIME: 'nodejs24.x', + NODE_VERSION: '24', + } + + logo = { + default: '/logos/cedarjs/default.png', + light: '/logos/cedarjs/default.png', + dark: '/logos/cedarjs/default.png', + } +} diff --git a/packages/build-info/src/frameworks/index.ts b/packages/build-info/src/frameworks/index.ts index e0ed370603..5a137869d0 100644 --- a/packages/build-info/src/frameworks/index.ts +++ b/packages/build-info/src/frameworks/index.ts @@ -5,6 +5,7 @@ import { Astro } from './astro.js' import { Blitz } from './blitz.js' import { Brunch } from './brunch.js' import { Cecil } from './cecil.js' +import { CedarJS } from './cedarjs.js' import { DocPad } from './docpad.js' import { Docusaurus } from './docusaurus.js' import { Eleventy } from './eleventy.js' @@ -56,6 +57,7 @@ import { Zola } from './zola.js' export const frameworks = [ // Static site generators / meta frameworks Astro, + CedarJS, Docusaurus, Eleventy, Gatsby, diff --git a/packages/build-info/src/project.ts b/packages/build-info/src/project.ts index fd7c385b5f..ba9b4a77c2 100644 --- a/packages/build-info/src/project.ts +++ b/packages/build-info/src/project.ts @@ -100,6 +100,10 @@ export class Project { return null } + async isCedarProject(): Promise { + return await this.fs.fileExists(this.fs.resolve(this.fs.cwd, 'cedar.toml')) + } + async isRedwoodProject(): Promise { return await this.fs.fileExists(this.fs.resolve(this.fs.cwd, 'redwood.toml')) } diff --git a/packages/build-info/src/workspaces/detect-workspace.ts b/packages/build-info/src/workspaces/detect-workspace.ts index 11ea3ca538..d252e75c04 100644 --- a/packages/build-info/src/workspaces/detect-workspace.ts +++ b/packages/build-info/src/workspaces/detect-workspace.ts @@ -78,7 +78,7 @@ export async function detectWorkspaces(project: Project): Promise