@mojojs/core
Version:
Real-time web framework
166 lines (155 loc) • 5.84 kB
JavaScript
import crypto from 'node:crypto';
import { version } from '../core.js';
import * as util from '../util.js';
import nopt from 'nopt';
/**
* Minimal application generator command.
*/
export default async function createFullAppCommand(app, args) {
const parsed = nopt({ ts: Boolean }, {}, args, 1);
const ts = parsed.ts === true;
process.stdout.write('Generating application directory structure:\n');
await util.cliCreateFile('config.yml', yamlConfig, { secret: crypto.randomBytes(16).toString('hex') });
await util.cliCreateDir('views/layouts');
await util.cliCreateFile('views/layouts/default.html.tmpl', tmplLayout);
await util.cliCreateDir('views/example');
await util.cliCreateFile('views/example/welcome.html.tmpl', tmplView);
await util.cliCreateDir('public/assets');
await util.cliCreateFile('public/index.html', staticFile);
// TypeScript
if (ts === true) {
await util.cliCreateDir('src');
await util.cliCreateFile('src/index.ts', jsIndex);
await util.cliCreateDir('src/controllers');
await util.cliCreateFile('src/controllers/example.ts', tsController);
await util.cliCreateDir('src/models');
await util.cliCreateDir('test');
await util.cliCreateFile('test/example.js', jsTest, { indexPath: '../lib/index.js' });
const tsConfig = {
compilerOptions: {
lib: ['ESNext', 'DOM'],
target: 'ES2020',
module: 'ES2020',
sourceMap: true,
declaration: true,
incremental: true,
moduleResolution: 'node',
esModuleInterop: true,
noErrorTruncation: true,
strict: true,
outDir: 'lib',
rootDir: 'src',
composite: true
},
include: ['src/**/*']
};
await util.cliCreateFile('tsconfig.json', JSON.stringify(tsConfig, null, 2));
await util.cliFixPackage({
dependencies: { '@mojojs/core': `^${version}` },
devDependencies: await util.devDependencies(/^(@types\/.+|nodemon|tap|typescript)$/),
scripts: {
build: 'npx tsc --build ./',
'build:test': 'npm run build && npm test',
'build:watch': 'npm run build -- --watch',
dev: 'npx nodemon lib/index.js server',
start: 'NODE_ENV=production node lib/index.js server -l http://*:8080',
test: 'node --test test/*.js'
}
});
}
// JavaScript
else {
await util.cliCreateFile('index.js', jsIndex);
await util.cliCreateDir('controllers');
await util.cliCreateFile('controllers/example.js', jsController);
await util.cliCreateDir('models');
await util.cliCreateDir('test');
await util.cliCreateFile('test/example.js', jsTest, { indexPath: '../index.js' });
await util.cliFixPackage({
dependencies: { '@mojojs/core': `^${version}` },
devDependencies: await util.devDependencies(/^(nodemon|tap)$/),
scripts: {
dev: 'npx nodemon index.js server',
start: 'NODE_ENV=production node index.js server -l http://*:8080',
test: 'node --test test/*.js'
}
});
}
}
createFullAppCommand.hidden = true;
createFullAppCommand.description = 'Create application directory structure';
createFullAppCommand.usage = `Usage: APPLICATION create-full-app [OPTIONS]
node index.js create-full-app
node index.js create-full-app --ts
Options:
-h, --help Show this summary of available options
--ts Generate TypeScript code instead of JavaScript
`;
const yamlConfig = `---
secrets:
- <%= secret %>
`;
const jsIndex = `import mojo, {yamlConfigPlugin} from '@mojojs/core';
export const app = mojo();
app.plugin(yamlConfigPlugin);
app.secrets = app.config.secrets;
app.get('/').to('example#welcome');
app.start();
`;
const jsController = `export default class Controller {
// Render template "example/welcome.html.tmpl" with message
async welcome (ctx) {
ctx.stash.msg = 'Welcome to the mojo.js real-time web framework!';
await ctx.render();
}
}
`;
const tsController = `import type {MojoContext} from '@mojojs/core';
export default class Controller {
// Render template "example/welcome.html.tmpl" with message
async welcome (ctx: MojoContext): Promise<void> {
ctx.stash.msg = 'Welcome to the mojo.js real-time web framework!';
await ctx.render();
}
}
`;
const tmplLayout = `<!DOCTYPE html>
<html>
<head>
%%= await tags.favicon()
<title>Welcome</title>
</head>
<body><%%= ctx.content.main %></body>
</html>
`;
const tmplView = `%% view.layout = 'default';
<h2><%%= msg %></h2>
<p>
This page was generated from the template "views/example/welcome.html.tmpl" and the layout
"views/layouts/default.html.tmpl", <a href="<%%= ctx.urlFor() %>">click here</a> to reload the page or
<a href="<%%= ctx.urlForFile('index.html') %>">here</a> to move forward to a static page.
</p>
`;
const staticFile = `<!DOCTYPE html>
<html>
<head>
<title>Welcome to the mojo.js real-time web framework!</title>
</head>
<body>
<h2>Welcome to the mojo.js real-time web framework!</h2>
This is the static document "public/index.html", <a href="/">click here</a> to get back to the start.
</body>
</html>
`;
const jsTest = `import {app} from '<%= indexPath %>';
import t from 'tap';
app.log.level = 'debug';
t.test('Example application', async t => {
const ua = await app.newTestUserAgent({tap: t});
await t.test('Index', async () => {
(await ua.getOk('/')).statusIs(200).bodyLike(/mojo.js/);
});
await ua.stop();
});
`;
//# sourceMappingURL=create-full-app.js.map