@aerogel/cli 0.0.0-next.47ed8ee3c048720794026e45140e9b700cb428b9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +7 -0
- package/bin/ag +4 -0
- package/dist/aerogel-cli.cjs.js +2 -0
- package/dist/aerogel-cli.cjs.js.map +1 -0
- package/dist/aerogel-cli.d.ts +10 -0
- package/dist/aerogel-cli.esm.js +2 -0
- package/dist/aerogel-cli.esm.js.map +1 -0
- package/noeldemartin.config.js +4 -0
- package/package.json +46 -0
- package/src/cli.ts +23 -0
- package/src/commands/Command.ts +59 -0
- package/src/commands/create.test.ts +26 -0
- package/src/commands/create.ts +69 -0
- package/src/commands/generate-component.test.ts +33 -0
- package/src/commands/generate-component.ts +65 -0
- package/src/commands/generate-model.test.ts +42 -0
- package/src/commands/generate-model.ts +81 -0
- package/src/lib/App.ts +25 -0
- package/src/lib/File.mock.ts +66 -0
- package/src/lib/File.ts +70 -0
- package/src/lib/Log.mock.ts +28 -0
- package/src/lib/Log.test.ts +21 -0
- package/src/lib/Log.ts +79 -0
- package/src/lib/Shell.mock.ts +20 -0
- package/src/lib/Shell.ts +28 -0
- package/src/lib/Template.ts +56 -0
- package/src/lib/utils.test.ts +33 -0
- package/src/lib/utils.ts +44 -0
- package/src/main.ts +3 -0
- package/src/testing/setup.ts +42 -0
- package/src/types/ts-reset.d.ts +1 -0
- package/templates/app/.github/workflows/ci.yml +17 -0
- package/templates/app/.gitignore.template +2 -0
- package/templates/app/.nvmrc +1 -0
- package/templates/app/cypress/e2e/app.cy.ts +9 -0
- package/templates/app/cypress/support/e2e.ts +3 -0
- package/templates/app/cypress/tsconfig.json +12 -0
- package/templates/app/cypress.config.ts +8 -0
- package/templates/app/index.html +12 -0
- package/templates/app/package.json +44 -0
- package/templates/app/postcss.config.js +6 -0
- package/templates/app/src/App.vue +10 -0
- package/templates/app/src/assets/styles.css +3 -0
- package/templates/app/src/lang/en.yaml +3 -0
- package/templates/app/src/main.test.ts +9 -0
- package/templates/app/src/main.ts +9 -0
- package/templates/app/src/types/globals.d.ts +3 -0
- package/templates/app/src/types/shims.d.ts +7 -0
- package/templates/app/src/types/ts-reset.d.ts +1 -0
- package/templates/app/tailwind.config.js +5 -0
- package/templates/app/tsconfig.json +18 -0
- package/templates/app/vite.config.ts +21 -0
- package/templates/component/[component.name].vue +3 -0
- package/templates/component-story/[component.name].story.vue +7 -0
- package/templates/model/[model.name].schema.ts +7 -0
- package/templates/model/[model.name].ts +3 -0
- package/tsconfig.json +11 -0
- package/vite.config.ts +14 -0
package/src/lib/File.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from 'fs';
|
|
2
|
+
import { facade } from '@noeldemartin/utils';
|
|
3
|
+
import { dirname, resolve } from 'path';
|
|
4
|
+
|
|
5
|
+
export class FileService {
|
|
6
|
+
|
|
7
|
+
public contains(path: string, contents: string): boolean {
|
|
8
|
+
return !!this.read(path)?.includes(contents);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
public exists(path: string): boolean {
|
|
12
|
+
return existsSync(path);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
public read(path: string): string | null {
|
|
16
|
+
if (!this.isFile(path)) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return readFileSync(path).toString();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
public getFiles(directoryPath: string): string[] {
|
|
24
|
+
const children = readdirSync(directoryPath, { withFileTypes: true });
|
|
25
|
+
const files: string[] = [];
|
|
26
|
+
|
|
27
|
+
for (const child of children) {
|
|
28
|
+
const path = resolve(directoryPath, child.name);
|
|
29
|
+
|
|
30
|
+
if (child.isDirectory()) {
|
|
31
|
+
files.push(...this.getFiles(path));
|
|
32
|
+
} else {
|
|
33
|
+
files.push(path);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return files;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
public isDirectory(path: string): boolean {
|
|
41
|
+
return this.exists(path) && lstatSync(path).isDirectory();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
public isFile(path: string): boolean {
|
|
45
|
+
return this.exists(path) && lstatSync(path).isFile();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
public isEmptyDirectory(path: string): boolean {
|
|
49
|
+
if (!this.isDirectory(path)) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return this.getFiles(path).length === 0;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
public makeDirectory(path: string): void {
|
|
57
|
+
mkdirSync(path, { recursive: true });
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
public write(path: string, contents: string): void {
|
|
61
|
+
if (!existsSync(dirname(path))) {
|
|
62
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
writeFileSync(path, contents);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export default facade(new FileService());
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { expect } from 'vitest';
|
|
2
|
+
import { arrayFrom, facade } from '@noeldemartin/utils';
|
|
3
|
+
|
|
4
|
+
import { LogService } from './Log';
|
|
5
|
+
|
|
6
|
+
export class LogServiceMock extends LogService {
|
|
7
|
+
|
|
8
|
+
private logs: string[] = [];
|
|
9
|
+
|
|
10
|
+
public expectLogged(message: string): void {
|
|
11
|
+
expect(this.logs, `Expected message "${message}" to have been logged`).toContain(message);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
protected log(messages: string | string[]): void {
|
|
15
|
+
this.logs.push(...arrayFrom(messages));
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
public fail(message: string): void {
|
|
19
|
+
throw new Error(`Fail: ${message}`);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
protected stdout(): void {
|
|
23
|
+
//
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export default facade(new LogServiceMock());
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { bold, hex } from 'chalk';
|
|
2
|
+
import { describe, it } from 'vitest';
|
|
3
|
+
|
|
4
|
+
import LogMock from '@/lib/Log.mock';
|
|
5
|
+
|
|
6
|
+
import Log from './Log';
|
|
7
|
+
|
|
8
|
+
describe('Log', () => {
|
|
9
|
+
|
|
10
|
+
it('renders markdown bold', () => {
|
|
11
|
+
// Arrange
|
|
12
|
+
const info = hex('#00ffff');
|
|
13
|
+
|
|
14
|
+
// Act
|
|
15
|
+
Log.info('Foo **bar**');
|
|
16
|
+
|
|
17
|
+
// Assert
|
|
18
|
+
LogMock.expectLogged(info(`Foo ${bold('bar')}`));
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
});
|
package/src/lib/Log.ts
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { arrayFrom, facade, stringMatchAll } from '@noeldemartin/utils';
|
|
2
|
+
import { bold, hex } from 'chalk';
|
|
3
|
+
import { clearLine, cursorTo } from 'readline';
|
|
4
|
+
|
|
5
|
+
export class LogService {
|
|
6
|
+
|
|
7
|
+
protected renderInfo = hex('#00ffff');
|
|
8
|
+
protected renderSuccess = hex('#00ff00');
|
|
9
|
+
protected renderError = hex('#ff0000');
|
|
10
|
+
|
|
11
|
+
public async animate<T>(message: string, operation: () => Promise<T>): Promise<T> {
|
|
12
|
+
const updateStdout = (end: string = '') => {
|
|
13
|
+
const progress = this.renderInfo(this.renderMarkdown(message) + '.'.repeat(frame % 4)) + end;
|
|
14
|
+
|
|
15
|
+
this.stdout(progress);
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
let frame = 0;
|
|
19
|
+
|
|
20
|
+
updateStdout();
|
|
21
|
+
|
|
22
|
+
const interval = setInterval(() => (frame++, updateStdout()), 1000);
|
|
23
|
+
const result = await operation();
|
|
24
|
+
|
|
25
|
+
clearInterval(interval);
|
|
26
|
+
updateStdout('\n');
|
|
27
|
+
|
|
28
|
+
return result;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
public info(messages: string | string[]): void {
|
|
32
|
+
arrayFrom(messages).forEach((message) => {
|
|
33
|
+
this.log(this.renderInfo(this.renderMarkdown(message)));
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
public error(messages: string | string[]): void {
|
|
38
|
+
arrayFrom(messages).forEach((message) => {
|
|
39
|
+
this.log(this.renderError(this.renderMarkdown(message)));
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
public fail(messages: string | string[]): void {
|
|
44
|
+
this.error(messages);
|
|
45
|
+
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
public success(messages: string | string[]): void {
|
|
50
|
+
arrayFrom(messages).forEach((message) => {
|
|
51
|
+
this.log(this.renderSuccess(this.renderMarkdown(message)));
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
protected renderMarkdown(message: string): string {
|
|
56
|
+
const matches = stringMatchAll<2>(message, /\*\*(.*)\*\*/g);
|
|
57
|
+
|
|
58
|
+
for (const match of matches) {
|
|
59
|
+
message = message.replace(match[0], bold(match[1]));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return message;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
protected log(messages: string | string[]): void {
|
|
66
|
+
// eslint-disable-next-line no-console
|
|
67
|
+
arrayFrom(messages).forEach((message) => console.log(message));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
protected stdout(message: string): void {
|
|
71
|
+
cursorTo(process.stdout, 0);
|
|
72
|
+
clearLine(process.stdout, 0);
|
|
73
|
+
|
|
74
|
+
process.stdout.write(message);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export default facade(new LogService());
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { expect } from 'vitest';
|
|
2
|
+
import { facade } from '@noeldemartin/utils';
|
|
3
|
+
|
|
4
|
+
import { ShellService } from './Shell';
|
|
5
|
+
|
|
6
|
+
export class ShellServiceMock extends ShellService {
|
|
7
|
+
|
|
8
|
+
private history: string[] = [];
|
|
9
|
+
|
|
10
|
+
public async run(command: string): Promise<void> {
|
|
11
|
+
this.history.push(command);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
public expectRan(command: string): void {
|
|
15
|
+
expect(this.history, `expected '${command}' command to have been executed`).toContain(command);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export default facade(new ShellServiceMock());
|
package/src/lib/Shell.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { exec } from 'child_process';
|
|
2
|
+
import { facade } from '@noeldemartin/utils';
|
|
3
|
+
|
|
4
|
+
export class ShellService {
|
|
5
|
+
|
|
6
|
+
private cwd: string | null = null;
|
|
7
|
+
|
|
8
|
+
public setWorkingDirectory(cwd: string): void {
|
|
9
|
+
this.cwd = cwd;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
public async run(command: string): Promise<void> {
|
|
13
|
+
await new Promise<void>((resolve, reject) => {
|
|
14
|
+
exec(command, { cwd: this.cwd ?? undefined }, (error) => {
|
|
15
|
+
if (error) {
|
|
16
|
+
reject(error);
|
|
17
|
+
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
resolve();
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export default facade(new ShellService());
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { readFileSync } from 'fs';
|
|
2
|
+
import { render } from 'mustache';
|
|
3
|
+
import { toString } from '@noeldemartin/utils';
|
|
4
|
+
|
|
5
|
+
import File from '@/lib/File';
|
|
6
|
+
|
|
7
|
+
export default class Template {
|
|
8
|
+
|
|
9
|
+
public static instantiate(path: string, destination: string, replacements: Record<string, unknown>): string[] {
|
|
10
|
+
const template = new Template(path);
|
|
11
|
+
|
|
12
|
+
return template.instantiate(destination, replacements);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
constructor(public path: string) {}
|
|
16
|
+
|
|
17
|
+
public instantiate(destination: string, replacements: Record<string, unknown> = {}): string[] {
|
|
18
|
+
const filenameReplacements = this.getFilenameReplacements(replacements);
|
|
19
|
+
const files: string[] = [];
|
|
20
|
+
destination = `${destination}/`.replace(/\/\//, '/');
|
|
21
|
+
|
|
22
|
+
for (const file of File.getFiles(this.path)) {
|
|
23
|
+
const relativePath = Object.entries(filenameReplacements).reduce(
|
|
24
|
+
(path, [match, replacement]) => path.replaceAll(match, replacement),
|
|
25
|
+
file.substring(this.path.length + 1),
|
|
26
|
+
);
|
|
27
|
+
const fileContents = readFileSync(file).toString();
|
|
28
|
+
const filePath =
|
|
29
|
+
destination + (relativePath.endsWith('.template') ? relativePath.slice(0, -9) : relativePath);
|
|
30
|
+
|
|
31
|
+
File.write(filePath, render(fileContents, replacements, undefined, ['<%', '%>']));
|
|
32
|
+
files.push(filePath);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return files;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
protected getFilenameReplacements(
|
|
39
|
+
replacements: Record<string, unknown>,
|
|
40
|
+
prefix: string = '',
|
|
41
|
+
): Record<string, string> {
|
|
42
|
+
return Object.entries(replacements).reduce((filenameReplacements, [key, value]) => {
|
|
43
|
+
if (typeof value === 'object') {
|
|
44
|
+
Object.assign(
|
|
45
|
+
filenameReplacements,
|
|
46
|
+
this.getFilenameReplacements(value as Record<string, unknown>, `${key}.`),
|
|
47
|
+
);
|
|
48
|
+
} else {
|
|
49
|
+
filenameReplacements[`[${prefix}${key}]`] = toString(value);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return filenameReplacements;
|
|
53
|
+
}, {} as Record<string, string>);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { formatCodeBlock } from './utils';
|
|
4
|
+
|
|
5
|
+
describe('Utils', () => {
|
|
6
|
+
|
|
7
|
+
it('Formats code blocks', () => {
|
|
8
|
+
// Arrange
|
|
9
|
+
const raw = `
|
|
10
|
+
|
|
11
|
+
const foo = 'bar';
|
|
12
|
+
|
|
13
|
+
if (foo) {
|
|
14
|
+
doSomething();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
`;
|
|
18
|
+
const formatted = [
|
|
19
|
+
'const foo = \'bar\';', //
|
|
20
|
+
'', //
|
|
21
|
+
'if (foo) {', //
|
|
22
|
+
' doSomething();', //
|
|
23
|
+
'}', //
|
|
24
|
+
].join('\n');
|
|
25
|
+
|
|
26
|
+
// Act
|
|
27
|
+
const actual = formatCodeBlock(raw);
|
|
28
|
+
|
|
29
|
+
// Assert
|
|
30
|
+
expect(actual).toEqual(formatted);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
});
|
package/src/lib/utils.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { resolve } from 'path';
|
|
2
|
+
|
|
3
|
+
export interface FormatCodeBlockOptions {
|
|
4
|
+
indent?: number;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function basePath(path: string): string {
|
|
8
|
+
return resolve(__dirname, '../', path);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function formatCodeBlock(code: string, options: FormatCodeBlockOptions = {}): string {
|
|
12
|
+
const lines = code.split('\n');
|
|
13
|
+
const indent = options.indent ?? 0;
|
|
14
|
+
let originalIndent = 0;
|
|
15
|
+
let formatted = '';
|
|
16
|
+
|
|
17
|
+
for (const line of lines) {
|
|
18
|
+
const trimmedLine = line.trim();
|
|
19
|
+
const isEmptyLine = trimmedLine.length === 0;
|
|
20
|
+
|
|
21
|
+
if (formatted.length === 0) {
|
|
22
|
+
if (isEmptyLine) {
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
originalIndent = line.indexOf(trimmedLine[0] ?? '');
|
|
27
|
+
formatted += `${' '.repeat(indent)}${trimmedLine}\n`;
|
|
28
|
+
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (isEmptyLine) {
|
|
33
|
+
formatted += '\n';
|
|
34
|
+
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const lineIndent = line.indexOf(trimmedLine[0] ?? '');
|
|
39
|
+
|
|
40
|
+
formatted += `${' '.repeat(indent + lineIndent - originalIndent)}${trimmedLine}\n`;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return formatted.trimEnd();
|
|
44
|
+
}
|
package/src/main.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { beforeEach, vi } from 'vitest';
|
|
2
|
+
import { resolve } from 'path';
|
|
3
|
+
import { setTestingNamespace } from '@noeldemartin/utils';
|
|
4
|
+
|
|
5
|
+
import File from '@/lib/File';
|
|
6
|
+
import FileMock from '@/lib/File.mock';
|
|
7
|
+
import Log from '@/lib/Log';
|
|
8
|
+
import LogMock from '@/lib/Log.mock';
|
|
9
|
+
import Shell from '@/lib/Shell';
|
|
10
|
+
import ShellMock from '@/lib/Shell.mock';
|
|
11
|
+
|
|
12
|
+
setTestingNamespace(vi);
|
|
13
|
+
|
|
14
|
+
File.setMockInstance(FileMock);
|
|
15
|
+
Log.setMockInstance(LogMock);
|
|
16
|
+
Shell.setMockInstance(ShellMock);
|
|
17
|
+
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
FileMock.reset();
|
|
20
|
+
File.mock();
|
|
21
|
+
Log.mock();
|
|
22
|
+
Shell.mock();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
// TODO find out why these need to be mocked
|
|
26
|
+
|
|
27
|
+
vi.mock('@/lib/utils', async () => {
|
|
28
|
+
const utils = (await vi.importActual('@/lib/utils')) as object;
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
...utils,
|
|
32
|
+
basePath(path: string) {
|
|
33
|
+
return resolve(__dirname, '../../', path);
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
vi.mock('mustache', async () => {
|
|
39
|
+
const mustache = (await vi.importActual('mustache')) as { default: unknown };
|
|
40
|
+
|
|
41
|
+
return mustache.default;
|
|
42
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/// <reference types="@total-typescript/ts-reset" />
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on: [push, pull_request]
|
|
4
|
+
|
|
5
|
+
jobs:
|
|
6
|
+
ci:
|
|
7
|
+
runs-on: ubuntu-latest
|
|
8
|
+
steps:
|
|
9
|
+
- uses: actions/checkout@v3
|
|
10
|
+
- uses: actions/setup-node@v3
|
|
11
|
+
with:
|
|
12
|
+
node-version-file: '.nvmrc'
|
|
13
|
+
- run: npm ci
|
|
14
|
+
- run: npm run lint
|
|
15
|
+
- run: npm run test:ci
|
|
16
|
+
- run: npm run cy:test
|
|
17
|
+
- run: npm run build
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
lts/hydrogen
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en" class="h-full w-full">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title><% app.name %></title>
|
|
7
|
+
</head>
|
|
8
|
+
<body class="h-full w-full">
|
|
9
|
+
<div id="app" class="h-full"></div>
|
|
10
|
+
<script type="module" src="./src/main.ts"></script>
|
|
11
|
+
</body>
|
|
12
|
+
</html>
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "<% app.slug %>",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"scripts": {
|
|
6
|
+
"build": "vite build",
|
|
7
|
+
"cy:dev": "concurrently --kill-others \"npm run test:serve-app\" \"npm run cy:open\"",
|
|
8
|
+
"cy:open": "cypress open --e2e --browser chromium",
|
|
9
|
+
"cy:run": "cypress run",
|
|
10
|
+
"cy:test": "start-server-and-test test:serve-app http-get://localhost:5001 cy:run",
|
|
11
|
+
"dev": "vite",
|
|
12
|
+
"lint": "noeldemartin-lint src",
|
|
13
|
+
"test": "vitest --run",
|
|
14
|
+
"test:ci": "vitest --run --reporter verbose",
|
|
15
|
+
"test:serve-app": "vite --port 5001"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@aerogel/core": "next",
|
|
19
|
+
"@aerogel/plugin-i18n": "next",
|
|
20
|
+
"@intlify/unplugin-vue-i18n": "^0.12.2",
|
|
21
|
+
"@tailwindcss/forms": "^0.5.3",
|
|
22
|
+
"@tailwindcss/typography": "^0.5.9",
|
|
23
|
+
"soukai": "^0.5.1",
|
|
24
|
+
"tailwindcss": "^3.3.2",
|
|
25
|
+
"vue": "^3.3.0",
|
|
26
|
+
"vue-i18n": "9.3.0-beta.19",
|
|
27
|
+
"vue-router": "^4.2.1"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@aerogel/cli": "next",
|
|
31
|
+
"@aerogel/cypress": "next",
|
|
32
|
+
"@aerogel/vite": "next",
|
|
33
|
+
"@noeldemartin/utils": "0.4.0-next.ac00beaecf32bb02ed8e335225d7948d946d73bd",
|
|
34
|
+
"@total-typescript/ts-reset": "^0.4.2",
|
|
35
|
+
"@types/node": "^20.3.1",
|
|
36
|
+
"autoprefixer": "^10.4.14",
|
|
37
|
+
"concurrently": "^8.2.0",
|
|
38
|
+
"cypress": "^12.17.0",
|
|
39
|
+
"start-server-and-test": "^2.0.0",
|
|
40
|
+
"unplugin-vue-components": "^0.24.1",
|
|
41
|
+
"vite": "^4.3.0",
|
|
42
|
+
"vitest": "^0.33.0"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<AGAppLayout>
|
|
3
|
+
<main class="flex flex-grow flex-col items-center justify-center bg-blue-50">
|
|
4
|
+
<h1 class="text-4xl font-semibold">{{ $t('home.title') }}</h1>
|
|
5
|
+
<a href="https://aerogel.js.org" target="_blank" class="mt-2 underline opacity-75 hover:opacity-100">
|
|
6
|
+
{{ $t('home.getStarted') }}
|
|
7
|
+
</a>
|
|
8
|
+
</main>
|
|
9
|
+
</AGAppLayout>
|
|
10
|
+
</template>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import i18n from '@aerogel/plugin-i18n';
|
|
2
|
+
import { bootstrapApplication } from '@aerogel/core';
|
|
3
|
+
|
|
4
|
+
import './assets/styles.css';
|
|
5
|
+
import App from './App.vue';
|
|
6
|
+
|
|
7
|
+
bootstrapApplication(App, {
|
|
8
|
+
plugins: [i18n({ messages: import.meta.glob('@/lang/*.yaml') })],
|
|
9
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/// <reference types="@total-typescript/ts-reset" />
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "esnext",
|
|
4
|
+
"module": "esnext",
|
|
5
|
+
"moduleResolution": "node",
|
|
6
|
+
"strict": true,
|
|
7
|
+
"jsx": "preserve",
|
|
8
|
+
"noUncheckedIndexedAccess": true,
|
|
9
|
+
"resolveJsonModule": true,
|
|
10
|
+
"esModuleInterop": true,
|
|
11
|
+
"lib": ["esnext", "dom"],
|
|
12
|
+
"baseUrl": ".",
|
|
13
|
+
"paths": {
|
|
14
|
+
"@/*": ["./src/*"]
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"include": ["src/**/*.ts", "src/**/*.vue"]
|
|
18
|
+
}
|