Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
"@eslint/eslintrc": "^3.3.0",
"@eslint/js": "^9.22.0",
"@junobuild/config": "^0.1.3",
"@junobuild/functions": "^0.0.12",
"@types/node": "^22.13.10",
"@types/prompts": "^2.4.9",
"@types/semver": "^7.5.8",
Expand Down
8 changes: 6 additions & 2 deletions src/commands/dev.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import {red} from 'kleur';
import {logHelpDevBuild} from '../help/dev.build.help';
import {logHelpDevEject} from '../help/dev.eject.help';
import {logHelpDev} from '../help/dev.help';
import {build} from '../services/build/build.services';
import {start, stop} from '../services/docker.services';
import {eject} from '../services/eject.services';
import {eject} from '../services/eject/eject.services';

export const dev = async (args?: string[]) => {
const [subCommand] = args ?? [];

switch (subCommand) {
case 'eject':
await eject();
await eject(args);
break;
case 'build':
await build(args);
Expand All @@ -34,6 +35,9 @@ export const helpDev = (args?: string[]) => {
case 'build':
logHelpDevBuild(args);
break;
case 'eject':
logHelpDevEject(args);
break;
default:
logHelpDev(args);
}
Expand Down
9 changes: 6 additions & 3 deletions src/constants/dev.constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ export const DEVELOPER_PROJECT_SATELLITE_DECLARATIONS_PATH = join(
);

export const CARGO_TOML = 'Cargo.toml';
export const INDEX_TS = "index.ts";
export const INDEX_MJS = "index.mjs";
export const INDEX_TS = 'index.ts';
export const INDEX_MJS = 'index.mjs';

export const DEVELOPER_PROJECT_SATELLITE_CARGO_TOML = join(
DEVELOPER_PROJECT_SATELLITE_PATH,
Expand All @@ -30,11 +30,14 @@ const TEMPLATE_PATH = '../templates/eject';
export const RUST_TEMPLATE_PATH = join(TEMPLATE_PATH, 'rust');
export const RUST_TEMPLATE_SATELLITE_PATH = join(RUST_TEMPLATE_PATH, 'src', 'satellite');

export const TS_TEMPLATE_PATH = join(TEMPLATE_PATH, 'typescript');
export const MJS_TEMPLATE_PATH = join(TEMPLATE_PATH, 'javascript');

export const RUST_MIN_VERSION = '1.70.0';
export const IC_WASM_MIN_VERSION = '0.8.5';
export const DOCKER_MIN_VERSION = '24.0.0';

export const DEPLOY_LOCAL_REPLICA_PATH = join(process.cwd(), 'target', 'deploy');

export const SPUTNIK_INDEX_MJS = "sputnik.index.mjs";
export const SPUTNIK_INDEX_MJS = 'sputnik.index.mjs';
export const DEPLOY_SPUTNIK_PATH = join(DEPLOY_LOCAL_REPLICA_PATH, SPUTNIK_INDEX_MJS);
4 changes: 2 additions & 2 deletions src/help/dev.build.help.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {cyan, green, magenta, yellow} from 'kleur';
import {helpOutput} from './common.help';
import {TITLE} from './help';

export const DEV_BUILD_DESCRIPTION = 'Build your serverless functions.';
const DEV_BUILD_DESCRIPTION = 'Build your serverless functions.';

const usage = `Usage: ${green('juno')} ${cyan('dev')} ${magenta('build')} ${yellow('[options]')}

Expand All @@ -15,7 +15,7 @@ Notes:

- If no language is provided, the CLI attempts to determine the appropriate build.
- Language can be shortened to ${magenta('rs')} for Rust, ${magenta('ts')} for TypeScript and ${magenta('js')} for JavaScript.
- The path option maps to ${magenta('--manifest-path')} for Rust (Cargo) or to the source file for TypeScript and JavaScript (e.g. ${magenta('index.ts')} or ${magenta('index.mjs')}) .`;
- The path option maps to ${magenta('--manifest-path')} for Rust (Cargo) or to the source file for TypeScript and JavaScript (e.g. ${magenta('index.ts')} or ${magenta('index.mjs')}).`;

const doc = `${DEV_BUILD_DESCRIPTION}

Expand Down
34 changes: 34 additions & 0 deletions src/help/dev.eject.help.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import {cyan, green, magenta, yellow} from 'kleur';
import {helpOutput} from './common.help';
import {TITLE} from './help';

export const DEV_EJECT_DESCRIPTION =
'Generate the required files to begin developing serverless functions in your project.';

const usage = `Usage: ${green('juno')} ${cyan('dev')} ${magenta('eject')} ${yellow('[options]')}

Options:
${yellow('-l, --lang')} Specify the language for building the serverless functions: ${magenta('rust')}, ${magenta('typescript')} or ${magenta('javascript')}.
${yellow('-h, --help')} Output usage information.

Notes:

- Language can be shortened to ${magenta('rs')} for Rust, ${magenta('ts')} for TypeScript and ${magenta('js')} for JavaScript.`;

const doc = `${DEV_EJECT_DESCRIPTION}

\`\`\`bash
${usage}
\`\`\`
`;

const help = `${TITLE}

${DEV_EJECT_DESCRIPTION}

${usage}
`;

export const logHelpDevEject = (args?: string[]) => {
console.log(helpOutput(args) === 'doc' ? doc : help);
};
58 changes: 0 additions & 58 deletions src/services/eject.services.ts

This file was deleted.

88 changes: 88 additions & 0 deletions src/services/eject/eject.javascript.services.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import {execute} from '@junobuild/cli-tools';
import {magenta} from 'kleur';
import {mkdir, readFile} from 'node:fs/promises';
import {join} from 'node:path';
import {
DEVELOPER_PROJECT_SATELLITE_PATH,
INDEX_MJS,
INDEX_TS,
MJS_TEMPLATE_PATH,
TS_TEMPLATE_PATH
} from '../../constants/dev.constants';
import {copyTemplateFile} from '../../utils/fs.utils';
import {detectPackageManager} from '../../utils/pm.utils';
import {confirmAndExit} from '../../utils/prompt.utils';

export const ejectTypeScript = async () => {
await eject({lang: 'ts'});
};

export const ejectJavaScript = async () => {
await eject({lang: 'mjs'});
};

const eject = async ({lang}: {lang: 'ts' | 'mjs'}) => {
await installFunctionsLib();

await createTargetDir();

await copyTemplateIndex({lang});

if (lang === 'ts') {
await copyTemplateTsConfig();
}
};

const copyTemplateIndex = async ({lang}: {lang: 'ts' | 'mjs'}) => {
await copyTemplateFile({
template: lang === 'mjs' ? INDEX_MJS : INDEX_TS,
sourceFolder: lang === 'mjs' ? MJS_TEMPLATE_PATH : TS_TEMPLATE_PATH,
destinationFolder: DEVELOPER_PROJECT_SATELLITE_PATH
});
};

const copyTemplateTsConfig = async () => {
await copyTemplateFile({
template: 'tsconfig.json',
sourceFolder: TS_TEMPLATE_PATH,
destinationFolder: DEVELOPER_PROJECT_SATELLITE_PATH
});
};

const createTargetDir = async () => {
const devProjectSrcPath = join(DEVELOPER_PROJECT_SATELLITE_PATH);
await mkdir(devProjectSrcPath, {recursive: true});
};

const installFunctionsLib = async () => {
const functionsAlreadyInstalled = await hasFunctionsLib();

if (functionsAlreadyInstalled) {
return;
}

await confirmAndExit(
`The ${magenta(
'@junobuild/functions'
)} library is required to develop serverless functions. Install it now?`
);

const pm = detectPackageManager();

await execute({
command: pm ?? 'npm',
args: [pm === 'npm' ? 'i' : 'add', '@junobuild/functions']
});
};

const hasFunctionsLib = async (): Promise<boolean> => {
try {
const packageJson = await readFile(join(process.cwd(), 'package.json'), 'utf-8');
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
const {dependencies} = JSON.parse(packageJson) as {dependencies?: Record<string, string>};
return Object.keys(dependencies ?? {}).includes('@junobuild/functions');
} catch (_err: unknown) {
// This should not block the developer therefore we fallback to asking for installing the library.
return false;
}
};
43 changes: 43 additions & 0 deletions src/services/eject/eject.rust.services.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import {mkdir} from 'node:fs/promises';
import {join} from 'node:path';
import {
CARGO_TOML,
DEVELOPER_PROJECT_SATELLITE_PATH,
RUST_TEMPLATE_PATH,
RUST_TEMPLATE_SATELLITE_PATH
} from '../../constants/dev.constants';
import {copySatelliteDid} from '../../utils/did.utils';
import {checkRustVersion} from '../../utils/env.utils';
import {copyTemplateFile} from '../../utils/fs.utils';

export const ejectRust = async () => {
const {valid} = await checkRustVersion();

if (valid === 'error' || !valid) {
return;
}

await copyTemplateFile({
template: CARGO_TOML,
sourceFolder: RUST_TEMPLATE_PATH,
destinationFolder: '.'
});

const devProjectSrcPath = join(DEVELOPER_PROJECT_SATELLITE_PATH, 'src');

await mkdir(devProjectSrcPath, {recursive: true});

await copyTemplateFile({
template: CARGO_TOML,
sourceFolder: RUST_TEMPLATE_SATELLITE_PATH,
destinationFolder: DEVELOPER_PROJECT_SATELLITE_PATH
});

await copyTemplateFile({
template: 'lib.rs',
sourceFolder: join(RUST_TEMPLATE_SATELLITE_PATH, 'src'),
destinationFolder: devProjectSrcPath
});

await copySatelliteDid();
};
Loading