chore: format code
This commit is contained in:
parent
a362adab90
commit
c25c5e03d4
35 changed files with 1365 additions and 615 deletions
|
@ -1,5 +1,5 @@
|
||||||
import globals from "globals";
|
import globals from 'globals'
|
||||||
import pluginJs from "@eslint/js";
|
import pluginJs from '@eslint/js'
|
||||||
|
|
||||||
/** @type {import('eslint').Linter.Config[]} */
|
/** @type {import('eslint').Linter.Config[]} */
|
||||||
export default [
|
export default [
|
||||||
|
@ -7,12 +7,12 @@ export default [
|
||||||
pluginJs.configs.recommended,
|
pluginJs.configs.recommended,
|
||||||
{
|
{
|
||||||
ignores: [
|
ignores: [
|
||||||
"dist/*",
|
'dist/*',
|
||||||
".output/*",
|
'.output/*',
|
||||||
".nitro/*",
|
'.nitro/*',
|
||||||
"node-modules*",
|
'node-modules*',
|
||||||
"site/*",
|
'site/*',
|
||||||
"templates/*",
|
'templates/*',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
]
|
||||||
|
|
|
@ -1,28 +1,28 @@
|
||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
import { consola } from "consola";
|
import { consola } from 'consola'
|
||||||
import { defineCommand } from "citty";
|
import { defineCommand } from 'citty'
|
||||||
import { execSync } from "node:child_process";
|
import { execSync } from 'node:child_process'
|
||||||
|
|
||||||
function build() {
|
function build() {
|
||||||
consola.start("Building project...");
|
consola.start('Building project...')
|
||||||
try {
|
try {
|
||||||
execSync(`npx nitropack build`, { stdio: "inherit" });
|
execSync(`npx nitropack build`, { stdio: 'inherit' })
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
consola.error(err);
|
consola.error(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default defineCommand({
|
export default defineCommand({
|
||||||
meta: {
|
meta: {
|
||||||
name: "prepare",
|
name: 'prepare',
|
||||||
description: "Builds the McFly project for production.",
|
description: 'Builds the McFly project for production.',
|
||||||
},
|
},
|
||||||
|
|
||||||
async run() {
|
async run() {
|
||||||
build()
|
build()
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
|
|
||||||
export const exportedForTest = {
|
export const exportedForTest = {
|
||||||
build,
|
build,
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
import { consola } from "consola";
|
import { consola } from 'consola'
|
||||||
import { defineCommand } from "citty";
|
import { defineCommand } from 'citty'
|
||||||
|
|
||||||
function generate() {
|
function generate() {
|
||||||
consola.box("Generate a McFly building block (In-progress)");
|
consola.box('Generate a McFly building block (In-progress)')
|
||||||
}
|
}
|
||||||
|
|
||||||
export default defineCommand({
|
export default defineCommand({
|
||||||
meta: {
|
meta: {
|
||||||
name: "prepare",
|
name: 'prepare',
|
||||||
description: "Generates building blocks for a McFly app.",
|
description: 'Generates building blocks for a McFly app.',
|
||||||
},
|
},
|
||||||
run() {
|
run() {
|
||||||
generate();
|
generate()
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
|
|
||||||
export const exportedForTest = {
|
export const exportedForTest = {
|
||||||
generate,
|
generate,
|
||||||
};
|
}
|
||||||
|
|
|
@ -1,43 +1,43 @@
|
||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
import { execSync } from "node:child_process";
|
import { execSync } from 'node:child_process'
|
||||||
import { consola } from "consola";
|
import { consola } from 'consola'
|
||||||
import { defineCommand } from "citty";
|
import { defineCommand } from 'citty'
|
||||||
|
|
||||||
function createNew(args) {
|
function createNew(args) {
|
||||||
const directory = args.dir || args._dir;
|
const directory = args.dir || args._dir
|
||||||
const command = directory
|
const command = directory
|
||||||
? `npm create mcfly@latest ${directory}`
|
? `npm create mcfly@latest ${directory}`
|
||||||
: "npm create mcfly@latest";
|
: 'npm create mcfly@latest'
|
||||||
try {
|
try {
|
||||||
execSync(command, { stdio: "inherit" });
|
execSync(command, { stdio: 'inherit' })
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
consola.error(e);
|
consola.error(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default defineCommand({
|
export default defineCommand({
|
||||||
meta: {
|
meta: {
|
||||||
name: "prepare",
|
name: 'prepare',
|
||||||
description: "Creates a new McFly project.",
|
description: 'Creates a new McFly project.',
|
||||||
},
|
},
|
||||||
args: {
|
args: {
|
||||||
dir: {
|
dir: {
|
||||||
type: "string",
|
type: 'string',
|
||||||
description: "project root directory",
|
description: 'project root directory',
|
||||||
required: false,
|
required: false,
|
||||||
},
|
},
|
||||||
_dir: {
|
_dir: {
|
||||||
type: "positional",
|
type: 'positional',
|
||||||
description: "project root directory (prefer using `--dir`)",
|
description: 'project root directory (prefer using `--dir`)',
|
||||||
required: false,
|
required: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
async run({ args }) {
|
async run({ args }) {
|
||||||
createNew(args)
|
createNew(args)
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
|
|
||||||
export const exportedForTest = {
|
export const exportedForTest = {
|
||||||
createNew
|
createNew,
|
||||||
}
|
}
|
|
@ -1,38 +1,38 @@
|
||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
import { consola } from "consola";
|
import { consola } from 'consola'
|
||||||
import { defineCommand } from "citty";
|
import { defineCommand } from 'citty'
|
||||||
import { execSync } from "node:child_process";
|
import { execSync } from 'node:child_process'
|
||||||
|
|
||||||
function prepare() {
|
function prepare() {
|
||||||
consola.start("Preparing McFly workspace...");
|
consola.start('Preparing McFly workspace...')
|
||||||
|
|
||||||
let err;
|
let err
|
||||||
|
|
||||||
try {
|
try {
|
||||||
execSync("npx nitropack prepare", { stdio: "inherit" });
|
execSync('npx nitropack prepare', { stdio: 'inherit' })
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
consola.error(e);
|
consola.error(e)
|
||||||
err = e;
|
err = e
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
consola.fail(
|
consola.fail(
|
||||||
"McFly workspace preparation failed. Please make sure dependencies are installed.\n"
|
'McFly workspace preparation failed. Please make sure dependencies are installed.\n'
|
||||||
);
|
)
|
||||||
} else consola.success("Done\n");
|
} else consola.success('Done\n')
|
||||||
}
|
}
|
||||||
|
|
||||||
export default defineCommand({
|
export default defineCommand({
|
||||||
meta: {
|
meta: {
|
||||||
name: "prepare",
|
name: 'prepare',
|
||||||
description: "Prepares the McFly workspace.",
|
description: 'Prepares the McFly workspace.',
|
||||||
},
|
},
|
||||||
run() {
|
run() {
|
||||||
prepare();
|
prepare()
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
|
|
||||||
export const exportedForTest = {
|
export const exportedForTest = {
|
||||||
prepare
|
prepare,
|
||||||
}
|
}
|
|
@ -1,46 +1,46 @@
|
||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
import { consola } from "consola";
|
import { consola } from 'consola'
|
||||||
import { colorize } from "consola/utils";
|
import { colorize } from 'consola/utils'
|
||||||
import { defineCommand } from "citty";
|
import { defineCommand } from 'citty'
|
||||||
import { execSync } from "node:child_process";
|
import { execSync } from 'node:child_process'
|
||||||
import { createRequire } from "node:module";
|
import { createRequire } from 'node:module'
|
||||||
|
|
||||||
async function printInfo() {
|
async function printInfo() {
|
||||||
try {
|
try {
|
||||||
const _require = createRequire(import.meta.url);
|
const _require = createRequire(import.meta.url)
|
||||||
const mcflyPkg = await _require("@mcflyjs/core/package.json");
|
const mcflyPkg = await _require('@mcflyjs/core/package.json')
|
||||||
const mcflyPkgVersion = `McFly ${colorize("bold", mcflyPkg.version)}`;
|
const mcflyPkgVersion = `McFly ${colorize('bold', mcflyPkg.version)}`
|
||||||
const nitroPkg = await _require("nitropack/package.json");
|
const nitroPkg = await _require('nitropack/package.json')
|
||||||
const nitroPkgVersion = `Nitro ${nitroPkg.version}`;
|
const nitroPkgVersion = `Nitro ${nitroPkg.version}`
|
||||||
consola.log(
|
consola.log(
|
||||||
`${colorize("blue", mcflyPkgVersion)} ${colorize("dim", nitroPkgVersion)}`
|
`${colorize('blue', mcflyPkgVersion)} ${colorize('dim', nitroPkgVersion)}`
|
||||||
);
|
)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
consola.error(e);
|
consola.error(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function serve() {
|
function serve() {
|
||||||
try {
|
try {
|
||||||
execSync(`npx nitropack dev`, { stdio: "inherit" });
|
execSync(`npx nitropack dev`, { stdio: 'inherit' })
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
consola.error(e);
|
consola.error(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default defineCommand({
|
export default defineCommand({
|
||||||
meta: {
|
meta: {
|
||||||
name: "prepare",
|
name: 'prepare',
|
||||||
description: "Runs the dev server.",
|
description: 'Runs the dev server.',
|
||||||
},
|
},
|
||||||
async run() {
|
async run() {
|
||||||
await printInfo();
|
await printInfo()
|
||||||
serve();
|
serve()
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
|
|
||||||
export const exportedForTest = {
|
export const exportedForTest = {
|
||||||
serve,
|
serve,
|
||||||
printInfo,
|
printInfo,
|
||||||
};
|
}
|
||||||
|
|
|
@ -1,23 +1,23 @@
|
||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
import { defineCommand, runMain } from "citty";
|
import { defineCommand, runMain } from 'citty'
|
||||||
|
|
||||||
const main = defineCommand({
|
const main = defineCommand({
|
||||||
meta: {
|
meta: {
|
||||||
name: "mcfly",
|
name: 'mcfly',
|
||||||
description: "McFly CLI",
|
description: 'McFly CLI',
|
||||||
},
|
},
|
||||||
subCommands: {
|
subCommands: {
|
||||||
new: () => import("./commands/new.mjs").then((r) => r.default),
|
new: () => import('./commands/new.mjs').then((r) => r.default),
|
||||||
serve: () => import("./commands/serve.mjs").then((r) => r.default),
|
serve: () => import('./commands/serve.mjs').then((r) => r.default),
|
||||||
build: () => import("./commands/build.mjs").then((r) => r.default),
|
build: () => import('./commands/build.mjs').then((r) => r.default),
|
||||||
prepare: () => import("./commands/prepare.mjs").then((r) => r.default),
|
prepare: () => import('./commands/prepare.mjs').then((r) => r.default),
|
||||||
generate: () => import("./commands/generate.mjs").then((r) => r.default),
|
generate: () => import('./commands/generate.mjs').then((r) => r.default),
|
||||||
g: () => import("./commands/generate.mjs").then((r) => r.default),
|
g: () => import('./commands/generate.mjs').then((r) => r.default),
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
|
|
||||||
runMain(main);
|
runMain(main)
|
||||||
|
|
||||||
export const exportedForTest = {
|
export const exportedForTest = {
|
||||||
main,
|
main,
|
||||||
};
|
}
|
||||||
|
|
|
@ -1,46 +1,46 @@
|
||||||
import consola from "consola";
|
import consola from 'consola'
|
||||||
import { vi, expect, test } from "vitest";
|
import { vi, expect, test } from 'vitest'
|
||||||
import { exportedForTest } from "../commands/build.mjs";
|
import { exportedForTest } from '../commands/build.mjs'
|
||||||
|
|
||||||
const testFn = exportedForTest.build;
|
const testFn = exportedForTest.build
|
||||||
|
|
||||||
const mocks = vi.hoisted(() => {
|
const mocks = vi.hoisted(() => {
|
||||||
return {
|
return {
|
||||||
execSync: vi.fn(),
|
execSync: vi.fn(),
|
||||||
};
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
vi.mock("node:child_process", () => {
|
vi.mock('node:child_process', () => {
|
||||||
return {
|
return {
|
||||||
execSync: mocks.execSync,
|
execSync: mocks.execSync,
|
||||||
};
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
test("start build with message", () => {
|
test('start build with message', () => {
|
||||||
const message = "Building project...";
|
const message = 'Building project...'
|
||||||
const spy = vi.spyOn(consola, "start");
|
const spy = vi.spyOn(consola, 'start')
|
||||||
|
|
||||||
testFn();
|
testFn()
|
||||||
|
|
||||||
expect(spy).toHaveBeenCalledWith(message);
|
expect(spy).toHaveBeenCalledWith(message)
|
||||||
});
|
})
|
||||||
|
|
||||||
test("execute nitropack build", () => {
|
test('execute nitropack build', () => {
|
||||||
const command = "npx nitropack build";
|
const command = 'npx nitropack build'
|
||||||
const param = { stdio: "inherit" };
|
const param = { stdio: 'inherit' }
|
||||||
|
|
||||||
testFn();
|
testFn()
|
||||||
|
|
||||||
expect(mocks.execSync).toHaveBeenCalledWith(command, param);
|
expect(mocks.execSync).toHaveBeenCalledWith(command, param)
|
||||||
});
|
})
|
||||||
|
|
||||||
test("catch error", () => {
|
test('catch error', () => {
|
||||||
const spy = vi.spyOn(consola, "error");
|
const spy = vi.spyOn(consola, 'error')
|
||||||
mocks.execSync.mockImplementationOnce(() => {
|
mocks.execSync.mockImplementationOnce(() => {
|
||||||
throw new Error("hey");
|
throw new Error('hey')
|
||||||
});
|
})
|
||||||
|
|
||||||
testFn();
|
testFn()
|
||||||
|
|
||||||
expect(spy).toHaveBeenCalledWith(new Error("hey"));
|
expect(spy).toHaveBeenCalledWith(new Error('hey'))
|
||||||
});
|
})
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
import { expect, test, vi } from "vitest";
|
import { expect, test, vi } from 'vitest'
|
||||||
import { exportedForTest } from "../commands/generate.mjs";
|
import { exportedForTest } from '../commands/generate.mjs'
|
||||||
import consola from "consola";
|
import consola from 'consola'
|
||||||
|
|
||||||
const testFn = exportedForTest.generate;
|
const testFn = exportedForTest.generate
|
||||||
|
|
||||||
test("show box message in-progress", () => {
|
test('show box message in-progress', () => {
|
||||||
const spy = vi.spyOn(consola, "box");
|
const spy = vi.spyOn(consola, 'box')
|
||||||
|
|
||||||
testFn();
|
testFn()
|
||||||
const arg = spy.mock.calls[0][0];
|
const arg = spy.mock.calls[0][0]
|
||||||
|
|
||||||
expect(spy).toHaveBeenCalled();
|
expect(spy).toHaveBeenCalled()
|
||||||
expect(arg).toContain("In-progress");
|
expect(arg).toContain('In-progress')
|
||||||
});
|
})
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import { test } from "vitest";
|
import { test } from 'vitest'
|
||||||
import { exportedForTest } from "..";
|
import { exportedForTest } from '..'
|
||||||
import { expect } from "vitest";
|
import { expect } from 'vitest'
|
||||||
|
|
||||||
const testObj = exportedForTest.main;
|
const testObj = exportedForTest.main
|
||||||
|
|
||||||
test("should have correct subcommands", () => {
|
test('should have correct subcommands', () => {
|
||||||
Object.keys(testObj.subCommands).forEach((key) => {
|
Object.keys(testObj.subCommands).forEach((key) => {
|
||||||
expect(testObj.subCommands[key]).toBeTypeOf("function");
|
expect(testObj.subCommands[key]).toBeTypeOf('function')
|
||||||
expect(testObj.subCommands[key].name).toBe(key);
|
expect(testObj.subCommands[key].name).toBe(key)
|
||||||
});
|
})
|
||||||
});
|
})
|
||||||
|
|
|
@ -1,79 +1,79 @@
|
||||||
import { expect, test, vi } from "vitest";
|
import { expect, test, vi } from 'vitest'
|
||||||
import { exportedForTest } from "../commands/new.mjs";
|
import { exportedForTest } from '../commands/new.mjs'
|
||||||
import { execSync } from "node:child_process";
|
import { execSync } from 'node:child_process'
|
||||||
import consola from "consola";
|
import consola from 'consola'
|
||||||
|
|
||||||
const testFn = exportedForTest.createNew;
|
const testFn = exportedForTest.createNew
|
||||||
const baseCommand = `npm create mcfly@latest`;
|
const baseCommand = `npm create mcfly@latest`
|
||||||
|
|
||||||
const mocks = vi.hoisted(() => {
|
const mocks = vi.hoisted(() => {
|
||||||
return {
|
return {
|
||||||
execSync: vi.fn(),
|
execSync: vi.fn(),
|
||||||
};
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
vi.mock("node:child_process", () => {
|
vi.mock('node:child_process', () => {
|
||||||
return {
|
return {
|
||||||
execSync: mocks.execSync,
|
execSync: mocks.execSync,
|
||||||
};
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
test("execute create mcfly", () => {
|
test('execute create mcfly', () => {
|
||||||
const param = { stdio: "inherit" };
|
const param = { stdio: 'inherit' }
|
||||||
|
|
||||||
testFn({ dir: undefined });
|
testFn({ dir: undefined })
|
||||||
|
|
||||||
expect(execSync).toHaveBeenCalledWith(baseCommand, param);
|
expect(execSync).toHaveBeenCalledWith(baseCommand, param)
|
||||||
});
|
})
|
||||||
|
|
||||||
test("execute create mcfly with no dir", () => {
|
test('execute create mcfly with no dir', () => {
|
||||||
const dir = "fake-dir";
|
const dir = 'fake-dir'
|
||||||
const command = `${baseCommand} ${dir}`;
|
const command = `${baseCommand} ${dir}`
|
||||||
const param = { stdio: "inherit" };
|
const param = { stdio: 'inherit' }
|
||||||
|
|
||||||
testFn({ dir: undefined });
|
testFn({ dir: undefined })
|
||||||
|
|
||||||
expect(execSync).not.toHaveBeenCalledWith(command, param);
|
expect(execSync).not.toHaveBeenCalledWith(command, param)
|
||||||
});
|
})
|
||||||
|
|
||||||
test("execute create mcfly with dir", () => {
|
test('execute create mcfly with dir', () => {
|
||||||
const dir = "fake-dir";
|
const dir = 'fake-dir'
|
||||||
const command = `${baseCommand} ${dir}`;
|
const command = `${baseCommand} ${dir}`
|
||||||
const param = { stdio: "inherit" };
|
const param = { stdio: 'inherit' }
|
||||||
|
|
||||||
testFn({ dir });
|
testFn({ dir })
|
||||||
|
|
||||||
expect(execSync).toHaveBeenCalledWith(command, param);
|
expect(execSync).toHaveBeenCalledWith(command, param)
|
||||||
});
|
})
|
||||||
|
|
||||||
test("execute create mcfly with _dir", () => {
|
test('execute create mcfly with _dir', () => {
|
||||||
const dir = "fake-dir";
|
const dir = 'fake-dir'
|
||||||
const command = `${baseCommand} ${dir}`;
|
const command = `${baseCommand} ${dir}`
|
||||||
const param = { stdio: "inherit" };
|
const param = { stdio: 'inherit' }
|
||||||
|
|
||||||
testFn({ _dir: dir });
|
testFn({ _dir: dir })
|
||||||
|
|
||||||
expect(execSync).toHaveBeenCalledWith(command, param);
|
expect(execSync).toHaveBeenCalledWith(command, param)
|
||||||
});
|
})
|
||||||
|
|
||||||
test("execute create mcfly with dir preferred over _dir", () => {
|
test('execute create mcfly with dir preferred over _dir', () => {
|
||||||
const dir = "preferred-dir";
|
const dir = 'preferred-dir'
|
||||||
const command = `${baseCommand} ${dir}`;
|
const command = `${baseCommand} ${dir}`
|
||||||
const param = { stdio: "inherit" };
|
const param = { stdio: 'inherit' }
|
||||||
|
|
||||||
testFn({ dir: dir, _dir: "not-preferred" });
|
testFn({ dir: dir, _dir: 'not-preferred' })
|
||||||
|
|
||||||
expect(execSync).toHaveBeenCalledWith(command, param);
|
expect(execSync).toHaveBeenCalledWith(command, param)
|
||||||
});
|
})
|
||||||
|
|
||||||
test("catch error", () => {
|
test('catch error', () => {
|
||||||
const dir = "fake-dir";
|
const dir = 'fake-dir'
|
||||||
const spy = vi.spyOn(consola, "error");
|
const spy = vi.spyOn(consola, 'error')
|
||||||
mocks.execSync.mockImplementationOnce(() => {
|
mocks.execSync.mockImplementationOnce(() => {
|
||||||
throw new Error("hey");
|
throw new Error('hey')
|
||||||
});
|
})
|
||||||
|
|
||||||
testFn({ dir });
|
testFn({ dir })
|
||||||
|
|
||||||
expect(spy).toHaveBeenCalledWith(new Error("hey"));
|
expect(spy).toHaveBeenCalledWith(new Error('hey'))
|
||||||
});
|
})
|
||||||
|
|
|
@ -1,50 +1,50 @@
|
||||||
import { test, expect, vi } from "vitest";
|
import { test, expect, vi } from 'vitest'
|
||||||
import { exportedForTest } from "../commands/prepare.mjs";
|
import { exportedForTest } from '../commands/prepare.mjs'
|
||||||
import consola from "consola";
|
import consola from 'consola'
|
||||||
import { execSync } from "node:child_process";
|
import { execSync } from 'node:child_process'
|
||||||
|
|
||||||
const testFn = exportedForTest.prepare;
|
const testFn = exportedForTest.prepare
|
||||||
|
|
||||||
const mocks = vi.hoisted(() => {
|
const mocks = vi.hoisted(() => {
|
||||||
return {
|
return {
|
||||||
execSync: vi.fn(),
|
execSync: vi.fn(),
|
||||||
};
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
vi.mock("node:child_process", () => {
|
vi.mock('node:child_process', () => {
|
||||||
return {
|
return {
|
||||||
execSync: mocks.execSync,
|
execSync: mocks.execSync,
|
||||||
};
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
test("start prepare script", () => {
|
test('start prepare script', () => {
|
||||||
const spy = vi.spyOn(consola, "start");
|
const spy = vi.spyOn(consola, 'start')
|
||||||
|
|
||||||
testFn();
|
testFn()
|
||||||
|
|
||||||
expect(spy).toHaveBeenCalled();
|
expect(spy).toHaveBeenCalled()
|
||||||
});
|
})
|
||||||
|
|
||||||
test("execute nitropack prepare", () => {
|
test('execute nitropack prepare', () => {
|
||||||
const successSpy = vi.spyOn(consola, "success");
|
const successSpy = vi.spyOn(consola, 'success')
|
||||||
const command = "npx nitropack prepare";
|
const command = 'npx nitropack prepare'
|
||||||
const param = { stdio: "inherit" };
|
const param = { stdio: 'inherit' }
|
||||||
|
|
||||||
testFn();
|
testFn()
|
||||||
|
|
||||||
expect(execSync).toHaveBeenCalledWith(command, param);
|
expect(execSync).toHaveBeenCalledWith(command, param)
|
||||||
expect(successSpy).toHaveBeenCalled();
|
expect(successSpy).toHaveBeenCalled()
|
||||||
});
|
})
|
||||||
|
|
||||||
test("catch error", () => {
|
test('catch error', () => {
|
||||||
const errSpy = vi.spyOn(consola, "error");
|
const errSpy = vi.spyOn(consola, 'error')
|
||||||
const failSpy = vi.spyOn(consola, "fail");
|
const failSpy = vi.spyOn(consola, 'fail')
|
||||||
mocks.execSync.mockImplementationOnce(() => {
|
mocks.execSync.mockImplementationOnce(() => {
|
||||||
throw new Error();
|
throw new Error()
|
||||||
});
|
})
|
||||||
|
|
||||||
testFn();
|
testFn()
|
||||||
|
|
||||||
expect(errSpy).toHaveBeenCalled();
|
expect(errSpy).toHaveBeenCalled()
|
||||||
expect(failSpy).toHaveBeenCalled();
|
expect(failSpy).toHaveBeenCalled()
|
||||||
});
|
})
|
||||||
|
|
|
@ -1,83 +1,83 @@
|
||||||
import { describe, expect, test, vi } from "vitest";
|
import { describe, expect, test, vi } from 'vitest'
|
||||||
import { exportedForTest } from "../commands/serve.mjs";
|
import { exportedForTest } from '../commands/serve.mjs'
|
||||||
import consola from "consola";
|
import consola from 'consola'
|
||||||
|
|
||||||
describe("FUNCTION: serve()", () => {
|
describe('FUNCTION: serve()', () => {
|
||||||
const testFn = exportedForTest.serve;
|
const testFn = exportedForTest.serve
|
||||||
const mocks = vi.hoisted(() => {
|
const mocks = vi.hoisted(() => {
|
||||||
return {
|
return {
|
||||||
execSync: vi.fn(),
|
execSync: vi.fn(),
|
||||||
};
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
vi.mock("node:child_process", () => {
|
vi.mock('node:child_process', () => {
|
||||||
return {
|
return {
|
||||||
execSync: mocks.execSync,
|
execSync: mocks.execSync,
|
||||||
};
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
test("execute nitropack serve", async () => {
|
test('execute nitropack serve', async () => {
|
||||||
const command = `npx nitropack dev`;
|
const command = `npx nitropack dev`
|
||||||
const param = { stdio: "inherit" };
|
const param = { stdio: 'inherit' }
|
||||||
|
|
||||||
testFn();
|
testFn()
|
||||||
|
|
||||||
expect(mocks.execSync).toHaveBeenCalledWith(command, param);
|
expect(mocks.execSync).toHaveBeenCalledWith(command, param)
|
||||||
});
|
})
|
||||||
|
|
||||||
test("catch error", () => {
|
test('catch error', () => {
|
||||||
const spy = vi.spyOn(consola, "error");
|
const spy = vi.spyOn(consola, 'error')
|
||||||
mocks.execSync.mockImplementationOnce(() => {
|
mocks.execSync.mockImplementationOnce(() => {
|
||||||
throw new Error("hey");
|
throw new Error('hey')
|
||||||
});
|
})
|
||||||
|
|
||||||
testFn();
|
testFn()
|
||||||
|
|
||||||
expect(spy).toHaveBeenCalledWith(new Error("hey"));
|
expect(spy).toHaveBeenCalledWith(new Error('hey'))
|
||||||
});
|
})
|
||||||
});
|
})
|
||||||
|
|
||||||
describe("FUNCTION: printInfo()", () => {
|
describe('FUNCTION: printInfo()', () => {
|
||||||
const testFn = exportedForTest.printInfo;
|
const testFn = exportedForTest.printInfo
|
||||||
|
|
||||||
const createRequireMocks = vi.hoisted(() => {
|
const createRequireMocks = vi.hoisted(() => {
|
||||||
return {
|
return {
|
||||||
createRequire: vi.fn(),
|
createRequire: vi.fn(),
|
||||||
};
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
vi.mock("node:module", () => {
|
vi.mock('node:module', () => {
|
||||||
return {
|
return {
|
||||||
createRequire: createRequireMocks.createRequire,
|
createRequire: createRequireMocks.createRequire,
|
||||||
};
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
test("log mcfly and nitro versions", async () => {
|
test('log mcfly and nitro versions', async () => {
|
||||||
const spy = vi.spyOn(consola, "log");
|
const spy = vi.spyOn(consola, 'log')
|
||||||
const fakeMessage = "McFly -1.0.0 Nitro -1.0.0";
|
const fakeMessage = 'McFly -1.0.0 Nitro -1.0.0'
|
||||||
createRequireMocks.createRequire.mockImplementationOnce(() => {
|
createRequireMocks.createRequire.mockImplementationOnce(() => {
|
||||||
return () => {
|
return () => {
|
||||||
return {
|
return {
|
||||||
version: "-1.0.0",
|
version: '-1.0.0',
|
||||||
};
|
}
|
||||||
};
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
await testFn();
|
await testFn()
|
||||||
|
|
||||||
expect(spy.mock.calls[0][0]).toContain("McFly");
|
expect(spy.mock.calls[0][0]).toContain('McFly')
|
||||||
expect(spy.mock.calls[0][0]).toContain("Nitro");
|
expect(spy.mock.calls[0][0]).toContain('Nitro')
|
||||||
expect(spy).toHaveBeenCalledWith(fakeMessage);
|
expect(spy).toHaveBeenCalledWith(fakeMessage)
|
||||||
});
|
})
|
||||||
|
|
||||||
test("catch error", async () => {
|
test('catch error', async () => {
|
||||||
createRequireMocks.createRequire.mockImplementationOnce(() => {
|
createRequireMocks.createRequire.mockImplementationOnce(() => {
|
||||||
throw new Error("error");
|
throw new Error('error')
|
||||||
});
|
})
|
||||||
const spy = vi.spyOn(consola, "error");
|
const spy = vi.spyOn(consola, 'error')
|
||||||
|
|
||||||
await testFn();
|
await testFn()
|
||||||
|
|
||||||
expect(spy).toHaveBeenCalledWith(new Error("error"));
|
expect(spy).toHaveBeenCalledWith(new Error('error'))
|
||||||
});
|
})
|
||||||
});
|
})
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import { coverageConfigDefaults, defineConfig } from "vitest/config";
|
import { coverageConfigDefaults, defineConfig } from 'vitest/config'
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
test: {
|
test: {
|
||||||
coverage: {
|
coverage: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
provider: "v8",
|
provider: 'v8',
|
||||||
reporter: ["html", "text"],
|
reporter: ['html', 'text'],
|
||||||
exclude: ["html/**", ...coverageConfigDefaults.exclude],
|
exclude: ['html/**', ...coverageConfigDefaults.exclude],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
|
|
|
@ -9,33 +9,33 @@
|
||||||
export default function () {
|
export default function () {
|
||||||
return {
|
return {
|
||||||
framework: {
|
framework: {
|
||||||
name: "McFly",
|
name: 'McFly',
|
||||||
},
|
},
|
||||||
compatibilityDate: "2024-12-08",
|
compatibilityDate: '2024-12-08',
|
||||||
devServer: {
|
devServer: {
|
||||||
watch: ["./src/pages", "./src/components"],
|
watch: ['./src/pages', './src/components'],
|
||||||
},
|
},
|
||||||
serverAssets: [
|
serverAssets: [
|
||||||
{
|
{
|
||||||
baseName: "pages",
|
baseName: 'pages',
|
||||||
dir: "./src/pages",
|
dir: './src/pages',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
baseName: "components",
|
baseName: 'components',
|
||||||
dir: "./src/components",
|
dir: './src/components',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
imports: {
|
imports: {
|
||||||
presets: [
|
presets: [
|
||||||
{
|
{
|
||||||
from: "web-component-base",
|
from: 'web-component-base',
|
||||||
imports: ["WebComponent", "html", "attachEffect"],
|
imports: ['WebComponent', 'html', 'attachEffect'],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
from: "@mcflyjs/core",
|
from: '@mcflyjs/core',
|
||||||
imports: ["useMcFlyRoute", "defineMcFlyConfig"],
|
imports: ['useMcFlyRoute', 'defineMcFlyConfig'],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,5 +10,5 @@
|
||||||
* @returns {function(): McFlyConfig}
|
* @returns {function(): McFlyConfig}
|
||||||
*/
|
*/
|
||||||
export function defineMcFlyConfig(config) {
|
export function defineMcFlyConfig(config) {
|
||||||
return () => config;
|
return () => config
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { eventHandler } from "h3";
|
import { eventHandler } from 'h3'
|
||||||
import { ELEMENT_NODE, parse, render, renderSync, walkSync } from "ultrahtml";
|
import { ELEMENT_NODE, parse, render, renderSync, walkSync } from 'ultrahtml'
|
||||||
import { parseScript } from "esprima";
|
import { parseScript } from 'esprima'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {import('./define-config.js').McFlyConfig} Config
|
* @typedef {import('./define-config.js').McFlyConfig} Config
|
||||||
|
@ -21,36 +21,36 @@ import { parseScript } from "esprima";
|
||||||
*/
|
*/
|
||||||
export function useMcFlyRoute({ config, storage }) {
|
export function useMcFlyRoute({ config, storage }) {
|
||||||
return eventHandler(async (event) => {
|
return eventHandler(async (event) => {
|
||||||
const { path } = event;
|
const { path } = event
|
||||||
const { components: componentType } = config();
|
const { components: componentType } = config()
|
||||||
let html = await getHtml(path, storage);
|
let html = await getHtml(path, storage)
|
||||||
|
|
||||||
if (html) {
|
if (html) {
|
||||||
const transforms = [doSetUp, deleteServerScripts];
|
const transforms = [doSetUp, deleteServerScripts]
|
||||||
|
|
||||||
for (const transform of transforms) {
|
for (const transform of transforms) {
|
||||||
html = transform(html.toString());
|
html = transform(html.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
html = await useFragments(html.toString(), storage);
|
html = await useFragments(html.toString(), storage)
|
||||||
|
|
||||||
if (!!componentType && !!html) {
|
if (!!componentType && !!html) {
|
||||||
html = await insertRegistry(html.toString(), componentType, storage);
|
html = await insertRegistry(html.toString(), componentType, storage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
html ??
|
html ??
|
||||||
new Response(
|
new Response(
|
||||||
"😱 ERROR 404: Not found. You can put a 404.html on the ./src/pages directory to customize this error page.",
|
'😱 ERROR 404: Not found. You can put a 404.html on the ./src/pages directory to customize this error page.',
|
||||||
{ status: 404 }
|
{ status: 404 }
|
||||||
)
|
)
|
||||||
);
|
)
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPurePath(path) {
|
function getPurePath(path) {
|
||||||
return path.split("?")[0];
|
return path.split('?')[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -60,17 +60,17 @@ function getPurePath(path) {
|
||||||
* @returns {Promise<StorageValue>}
|
* @returns {Promise<StorageValue>}
|
||||||
*/
|
*/
|
||||||
async function getHtml(path, storage) {
|
async function getHtml(path, storage) {
|
||||||
const purePath = getPurePath(path);
|
const purePath = getPurePath(path)
|
||||||
const rawPath =
|
const rawPath =
|
||||||
purePath[purePath.length - 1] === "/" ? purePath.slice(0, -1) : purePath;
|
purePath[purePath.length - 1] === '/' ? purePath.slice(0, -1) : purePath
|
||||||
const filename = rawPath === "" ? "/index.html" : `${rawPath}.html`;
|
const filename = rawPath === '' ? '/index.html' : `${rawPath}.html`
|
||||||
const fallback = getPath(rawPath + "/index.html");
|
const fallback = getPath(rawPath + '/index.html')
|
||||||
const filePath = getPath(filename);
|
const filePath = getPath(filename)
|
||||||
let html = await storage.getItem(filePath);
|
let html = await storage.getItem(filePath)
|
||||||
if (!html) html = await storage.getItem(fallback);
|
if (!html) html = await storage.getItem(fallback)
|
||||||
if (!html) html = await storage.getItem(getPath("/404.html"));
|
if (!html) html = await storage.getItem(getPath('/404.html'))
|
||||||
|
|
||||||
return html;
|
return html
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -79,7 +79,7 @@ async function getHtml(path, storage) {
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
function getPath(filename) {
|
function getPath(filename) {
|
||||||
return `assets:pages${filename}`;
|
return `assets:pages${filename}`
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -90,21 +90,21 @@ function getPath(filename) {
|
||||||
* @returns {Promise<string>}
|
* @returns {Promise<string>}
|
||||||
*/
|
*/
|
||||||
async function insertRegistry(html, type, storage) {
|
async function insertRegistry(html, type, storage) {
|
||||||
const ast = parse(html);
|
const ast = parse(html)
|
||||||
const componentFiles = await getFiles(type, storage);
|
const componentFiles = await getFiles(type, storage)
|
||||||
const availableComponents = componentFiles.map((key) =>
|
const availableComponents = componentFiles.map((key) =>
|
||||||
key.replace(`.${type}`, "")
|
key.replace(`.${type}`, '')
|
||||||
);
|
)
|
||||||
|
|
||||||
const usedCustomElements = [];
|
const usedCustomElements = []
|
||||||
|
|
||||||
walkSync(ast, (node) => {
|
walkSync(ast, (node) => {
|
||||||
const usedElement = availableComponents.find((name) => name === node.name);
|
const usedElement = availableComponents.find((name) => name === node.name)
|
||||||
|
|
||||||
if (node.type === ELEMENT_NODE && !!usedElement) {
|
if (node.type === ELEMENT_NODE && !!usedElement) {
|
||||||
usedCustomElements.push(usedElement);
|
usedCustomElements.push(usedElement)
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
// insert registry script to head
|
// insert registry script to head
|
||||||
if (usedCustomElements.length > 0) {
|
if (usedCustomElements.length > 0) {
|
||||||
|
@ -112,15 +112,15 @@ async function insertRegistry(html, type, storage) {
|
||||||
usedCustomElements,
|
usedCustomElements,
|
||||||
type,
|
type,
|
||||||
storage
|
storage
|
||||||
);
|
)
|
||||||
walkSync(ast, (node) => {
|
walkSync(ast, (node) => {
|
||||||
if (node.type === ELEMENT_NODE && node.name === "head") {
|
if (node.type === ELEMENT_NODE && node.name === 'head') {
|
||||||
node.children.push(parse(registryScript));
|
node.children.push(parse(registryScript))
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return render(ast);
|
return render(ast)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -131,41 +131,41 @@ async function insertRegistry(html, type, storage) {
|
||||||
* @returns {Promise<string>}
|
* @returns {Promise<string>}
|
||||||
*/
|
*/
|
||||||
async function buildRegistry(usedCustomElements, type, storage) {
|
async function buildRegistry(usedCustomElements, type, storage) {
|
||||||
let registryScript = `<script type='module'>`;
|
let registryScript = `<script type='module'>`
|
||||||
let isBaseClassImported = false;
|
let isBaseClassImported = false
|
||||||
let classesImported = [];
|
let classesImported = []
|
||||||
|
|
||||||
for (const name of usedCustomElements) {
|
for (const name of usedCustomElements) {
|
||||||
const content = await storage.getItem(`assets:components:${name}.${type}`);
|
const content = await storage.getItem(`assets:components:${name}.${type}`)
|
||||||
if (!content) continue;
|
if (!content) continue
|
||||||
const evalStore = eval(
|
const evalStore = eval(
|
||||||
`class WebComponent {}; class HTMLElement {}; (${content.toString()})`
|
`class WebComponent {}; class HTMLElement {}; (${content.toString()})`
|
||||||
);
|
)
|
||||||
|
|
||||||
if (isConstructor(evalStore)) {
|
if (isConstructor(evalStore)) {
|
||||||
const className = new evalStore().constructor.name;
|
const className = new evalStore().constructor.name
|
||||||
|
|
||||||
if (!classesImported.includes(className)) {
|
if (!classesImported.includes(className)) {
|
||||||
if (
|
if (
|
||||||
!isBaseClassImported &&
|
!isBaseClassImported &&
|
||||||
content.toString().includes("extends WebComponent")
|
content.toString().includes('extends WebComponent')
|
||||||
) {
|
) {
|
||||||
const baseClassImport = `import { WebComponent, html, attachEffect } from "https://unpkg.com/web-component-base@2.0.6/index.js";`;
|
const baseClassImport = `import { WebComponent, html, attachEffect } from "https://unpkg.com/web-component-base@2.0.6/index.js";`
|
||||||
registryScript += baseClassImport;
|
registryScript += baseClassImport
|
||||||
isBaseClassImported = true;
|
isBaseClassImported = true
|
||||||
}
|
}
|
||||||
|
|
||||||
registryScript += content;
|
registryScript += content
|
||||||
|
|
||||||
registryScript += `customElements.define("${name}", ${className});`;
|
registryScript += `customElements.define("${name}", ${className});`
|
||||||
classesImported.push(className);
|
classesImported.push(className)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
registryScript += "</script>";
|
registryScript += '</script>'
|
||||||
|
|
||||||
return registryScript;
|
return registryScript
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -175,13 +175,13 @@ async function buildRegistry(usedCustomElements, type, storage) {
|
||||||
*/
|
*/
|
||||||
function isConstructor(f) {
|
function isConstructor(f) {
|
||||||
try {
|
try {
|
||||||
new f();
|
new f()
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// TODO: verify err is the expected error and then
|
// TODO: verify err is the expected error and then
|
||||||
return false;
|
return false
|
||||||
}
|
}
|
||||||
return true;
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -190,56 +190,56 @@ function isConstructor(f) {
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
function doSetUp(html) {
|
function doSetUp(html) {
|
||||||
const ast = parse(html);
|
const ast = parse(html)
|
||||||
const serverScripts = [];
|
const serverScripts = []
|
||||||
walkSync(ast, (node) => {
|
walkSync(ast, (node) => {
|
||||||
const { attributes } = node;
|
const { attributes } = node
|
||||||
const attributeKeys = Object.keys(attributes ?? {});
|
const attributeKeys = Object.keys(attributes ?? {})
|
||||||
const isServerScript = attributeKeys.some((key) => key.includes("server:"));
|
const isServerScript = attributeKeys.some((key) => key.includes('server:'))
|
||||||
if (
|
if (
|
||||||
node.type === ELEMENT_NODE &&
|
node.type === ELEMENT_NODE &&
|
||||||
node.name === "script" &&
|
node.name === 'script' &&
|
||||||
isServerScript
|
isServerScript
|
||||||
) {
|
) {
|
||||||
const scripts = node.children.map((child) => child.value);
|
const scripts = node.children.map((child) => child.value)
|
||||||
const script = cleanScript(scripts);
|
const script = cleanScript(scripts)
|
||||||
serverScripts.push(script);
|
serverScripts.push(script)
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
const setupMap = {};
|
const setupMap = {}
|
||||||
serverScripts.forEach((script) => {
|
serverScripts.forEach((script) => {
|
||||||
const { body } = parseScript(script);
|
const { body } = parseScript(script)
|
||||||
const keys = body
|
const keys = body
|
||||||
.filter((n) => n.type === "VariableDeclaration")
|
.filter((n) => n.type === 'VariableDeclaration')
|
||||||
.map((n) => n["declarations"][0].id.name);
|
.map((n) => n['declarations'][0].id.name)
|
||||||
const constructor = `(function(){}.constructor)(\`${script}; return {${keys.join(
|
const constructor = `(function(){}.constructor)(\`${script}; return {${keys.join(
|
||||||
","
|
','
|
||||||
)}}\`);`;
|
)}}\`);`
|
||||||
const evalStore = eval(constructor);
|
const evalStore = eval(constructor)
|
||||||
Object.assign(setupMap, new evalStore());
|
Object.assign(setupMap, new evalStore())
|
||||||
});
|
})
|
||||||
|
|
||||||
const regex = /{{(.*?)}}/g;
|
const regex = /{{(.*?)}}/g
|
||||||
let match;
|
let match
|
||||||
|
|
||||||
while ((match = regex.exec(html))) {
|
while ((match = regex.exec(html))) {
|
||||||
let [key, value] = match;
|
let [key, value] = match
|
||||||
value = value.replace(/\s/g, "");
|
value = value.replace(/\s/g, '')
|
||||||
// nested objects
|
// nested objects
|
||||||
const keys = value.split(".");
|
const keys = value.split('.')
|
||||||
let finalValue = "";
|
let finalValue = ''
|
||||||
let setupCopy = setupMap;
|
let setupCopy = setupMap
|
||||||
|
|
||||||
keys.forEach((i) => {
|
keys.forEach((i) => {
|
||||||
finalValue = setupCopy[i];
|
finalValue = setupCopy[i]
|
||||||
setupCopy = finalValue;
|
setupCopy = finalValue
|
||||||
});
|
})
|
||||||
|
|
||||||
html = html.replace(key, finalValue);
|
html = html.replace(key, finalValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
return html;
|
return html
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -248,17 +248,17 @@ function doSetUp(html) {
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
function deleteServerScripts(html) {
|
function deleteServerScripts(html) {
|
||||||
const ast = parse(html);
|
const ast = parse(html)
|
||||||
walkSync(ast, (node) => {
|
walkSync(ast, (node) => {
|
||||||
const { attributes } = node;
|
const { attributes } = node
|
||||||
const attributeKeys = Object.keys(attributes ?? {});
|
const attributeKeys = Object.keys(attributes ?? {})
|
||||||
const isServerScript = attributeKeys.some((key) => key.includes("server:"));
|
const isServerScript = attributeKeys.some((key) => key.includes('server:'))
|
||||||
if (isServerScript && !!node.parent) {
|
if (isServerScript && !!node.parent) {
|
||||||
node.parent.children.splice(node.parent.children.indexOf(node), 1);
|
node.parent.children.splice(node.parent.children.indexOf(node), 1)
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
return renderSync(ast);
|
return renderSync(ast)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -267,11 +267,11 @@ function deleteServerScripts(html) {
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
function cleanScript(scripts) {
|
function cleanScript(scripts) {
|
||||||
let script = scripts.map((s) => s.trim()).join(" ");
|
let script = scripts.map((s) => s.trim()).join(' ')
|
||||||
|
|
||||||
script = removeComments(script);
|
script = removeComments(script)
|
||||||
|
|
||||||
return script.replace(/\n/g, "").replace(/\s+/g, " ");
|
return script.replace(/\n/g, '').replace(/\s+/g, ' ')
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -281,11 +281,11 @@ function cleanScript(scripts) {
|
||||||
*/
|
*/
|
||||||
function isComment(node) {
|
function isComment(node) {
|
||||||
return (
|
return (
|
||||||
node.type === "Line" ||
|
node.type === 'Line' ||
|
||||||
node.type === "Block" ||
|
node.type === 'Block' ||
|
||||||
node.type === "BlockComment" ||
|
node.type === 'BlockComment' ||
|
||||||
node.type === "LineComment"
|
node.type === 'LineComment'
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -294,25 +294,25 @@ function isComment(node) {
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
function removeComments(script) {
|
function removeComments(script) {
|
||||||
const entries = [];
|
const entries = []
|
||||||
parseScript(script, { comment: true }, function (node, meta) {
|
parseScript(script, { comment: true }, function (node, meta) {
|
||||||
if (isComment(node)) {
|
if (isComment(node)) {
|
||||||
entries.push({
|
entries.push({
|
||||||
start: meta.start.offset,
|
start: meta.start.offset,
|
||||||
end: meta.end.offset,
|
end: meta.end.offset,
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
entries
|
entries
|
||||||
.sort((a, b) => {
|
.sort((a, b) => {
|
||||||
return b.end - a.end;
|
return b.end - a.end
|
||||||
})
|
})
|
||||||
.forEach((n) => {
|
.forEach((n) => {
|
||||||
script = script.slice(0, n.start) + script.slice(n.end);
|
script = script.slice(0, n.start) + script.slice(n.end)
|
||||||
});
|
})
|
||||||
|
|
||||||
return script;
|
return script
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -322,44 +322,44 @@ function removeComments(script) {
|
||||||
* @returns {Promise<string>}
|
* @returns {Promise<string>}
|
||||||
*/
|
*/
|
||||||
async function useFragments(html, storage) {
|
async function useFragments(html, storage) {
|
||||||
const fragmentFiles = await getFiles("html", storage);
|
const fragmentFiles = await getFiles('html', storage)
|
||||||
|
|
||||||
const availableFragments = fragmentFiles.reduce((acc, key) => {
|
const availableFragments = fragmentFiles.reduce((acc, key) => {
|
||||||
return {
|
return {
|
||||||
...acc,
|
...acc,
|
||||||
[key.replace(".html", "")]: "",
|
[key.replace('.html', '')]: '',
|
||||||
};
|
}
|
||||||
}, {});
|
}, {})
|
||||||
const ast = parse(html);
|
const ast = parse(html)
|
||||||
|
|
||||||
for (const key in availableFragments) {
|
for (const key in availableFragments) {
|
||||||
/**
|
/**
|
||||||
* @type string | null
|
* @type string | null
|
||||||
*/
|
*/
|
||||||
let text = await storage.getItem("assets:components:" + key + ".html");
|
let text = await storage.getItem('assets:components:' + key + '.html')
|
||||||
if (!text) continue;
|
if (!text) continue
|
||||||
availableFragments[key] = text.replace(/\n/g, "").replace(/\s+/g, " ");
|
availableFragments[key] = text.replace(/\n/g, '').replace(/\s+/g, ' ')
|
||||||
}
|
}
|
||||||
|
|
||||||
walkSync(ast, (node) => {
|
walkSync(ast, (node) => {
|
||||||
const selector = Object.keys(availableFragments).find(
|
const selector = Object.keys(availableFragments).find(
|
||||||
(name) => name === node.name
|
(name) => name === node.name
|
||||||
);
|
)
|
||||||
|
|
||||||
if (node.type === ELEMENT_NODE && !!selector) {
|
if (node.type === ELEMENT_NODE && !!selector) {
|
||||||
const index = node.parent.children.indexOf(node);
|
const index = node.parent.children.indexOf(node)
|
||||||
/**
|
/**
|
||||||
* @type {HtmlNode}
|
* @type {HtmlNode}
|
||||||
*/
|
*/
|
||||||
const fragmentNode = parse(availableFragments[selector]);
|
const fragmentNode = parse(availableFragments[selector])
|
||||||
|
|
||||||
replaceSlots(fragmentNode, node);
|
replaceSlots(fragmentNode, node)
|
||||||
|
|
||||||
node.parent.children[index] = fragmentNode;
|
node.parent.children[index] = fragmentNode
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
return render(ast);
|
return render(ast)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -369,32 +369,32 @@ async function useFragments(html, storage) {
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
function replaceSlots(fragmentNode, node) {
|
function replaceSlots(fragmentNode, node) {
|
||||||
let slotted = [];
|
let slotted = []
|
||||||
const containsAll = (arr, target) => target.every((v) => arr.includes(v));
|
const containsAll = (arr, target) => target.every((v) => arr.includes(v))
|
||||||
walkSync(fragmentNode, (n) => {
|
walkSync(fragmentNode, (n) => {
|
||||||
if (n.type === ELEMENT_NODE && n.name === "slot") {
|
if (n.type === ELEMENT_NODE && n.name === 'slot') {
|
||||||
// find node child with same name attribute
|
// find node child with same name attribute
|
||||||
const currentSlotName = n.attributes?.["name"] ?? null;
|
const currentSlotName = n.attributes?.['name'] ?? null
|
||||||
let nodeChildren = [];
|
let nodeChildren = []
|
||||||
|
|
||||||
if (currentSlotName === null) {
|
if (currentSlotName === null) {
|
||||||
nodeChildren = node.children.filter(
|
nodeChildren = node.children.filter(
|
||||||
(child) => !child.attributes?.["slot"]
|
(child) => !child.attributes?.['slot']
|
||||||
);
|
)
|
||||||
} else {
|
} else {
|
||||||
nodeChildren = node.children.filter((child) => {
|
nodeChildren = node.children.filter((child) => {
|
||||||
const childSlotName = child.attributes?.["slot"];
|
const childSlotName = child.attributes?.['slot']
|
||||||
return childSlotName === currentSlotName;
|
return childSlotName === currentSlotName
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nodeChildren.length > 0 && !containsAll(slotted, nodeChildren)) {
|
if (nodeChildren.length > 0 && !containsAll(slotted, nodeChildren)) {
|
||||||
slotted = [...slotted, ...nodeChildren];
|
slotted = [...slotted, ...nodeChildren]
|
||||||
const index = n.parent.children.indexOf(n);
|
const index = n.parent.children.indexOf(n)
|
||||||
n.parent.children.splice(index, 1, ...nodeChildren);
|
n.parent.children.splice(index, 1, ...nodeChildren)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -404,7 +404,7 @@ function replaceSlots(fragmentNode, node) {
|
||||||
* @returns {Promise<string[]>}
|
* @returns {Promise<string[]>}
|
||||||
*/
|
*/
|
||||||
async function getFiles(type, storage) {
|
async function getFiles(type, storage) {
|
||||||
return (await storage.getKeys("assets:components"))
|
return (await storage.getKeys('assets:components'))
|
||||||
.map((key) => key.replace("assets:components:", ""))
|
.map((key) => key.replace('assets:components:', ''))
|
||||||
.filter((key) => key.includes(type));
|
.filter((key) => key.includes(type))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
export { defineMcFlyConfig } from "./define-config.js";
|
export { defineMcFlyConfig } from './define-config.js'
|
||||||
export { useMcFlyRoute } from "./event-handler.js";
|
export { useMcFlyRoute } from './event-handler.js'
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
import { consola } from "consola";
|
import { consola } from 'consola'
|
||||||
import { colorize } from "consola/utils";
|
import { colorize } from 'consola/utils'
|
||||||
import { downloadTemplate } from "giget";
|
import { downloadTemplate } from 'giget'
|
||||||
import { spawnSync } from "node:child_process";
|
import { spawnSync } from 'node:child_process'
|
||||||
import path from "node:path";
|
import path from 'node:path'
|
||||||
|
|
||||||
const [, , directoryArg] = process.argv;
|
const [, , directoryArg] = process.argv
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {{
|
* @typedef {{
|
||||||
|
@ -23,25 +23,25 @@ const [, , directoryArg] = process.argv;
|
||||||
* Create McFly App
|
* Create McFly App
|
||||||
*/
|
*/
|
||||||
async function create() {
|
async function create() {
|
||||||
const defaultDirectory = "mcfly-app";
|
const defaultDirectory = 'mcfly-app'
|
||||||
consola.box(`Hello! Welcome to ${colorize("bold", "McFly")}!`);
|
consola.box(`Hello! Welcome to ${colorize('bold', 'McFly')}!`)
|
||||||
let directory = directoryArg;
|
let directory = directoryArg
|
||||||
|
|
||||||
if (!directory) {
|
if (!directory) {
|
||||||
directory =
|
directory =
|
||||||
(await consola.prompt("Give your new project a name:", {
|
(await consola.prompt('Give your new project a name:', {
|
||||||
placeholder: defaultDirectory,
|
placeholder: defaultDirectory,
|
||||||
})) ?? defaultDirectory;
|
})) ?? defaultDirectory
|
||||||
} else {
|
} else {
|
||||||
consola.success(`Using ${directory} as name.`);
|
consola.success(`Using ${directory} as name.`)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof directory !== "string") {
|
if (typeof directory !== 'string') {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
directory = getSafeDirectory(directory);
|
directory = getSafeDirectory(directory)
|
||||||
const hasErrors = await downloadTemplateToDirectory(directory);
|
const hasErrors = await downloadTemplateToDirectory(directory)
|
||||||
|
|
||||||
if (!hasErrors) {
|
if (!hasErrors) {
|
||||||
/**
|
/**
|
||||||
|
@ -50,33 +50,33 @@ async function create() {
|
||||||
const prompts = [
|
const prompts = [
|
||||||
{
|
{
|
||||||
prompt: `Would you like to install the dependencies to ${colorize(
|
prompt: `Would you like to install the dependencies to ${colorize(
|
||||||
"bold",
|
'bold',
|
||||||
directory
|
directory
|
||||||
)}?`,
|
)}?`,
|
||||||
info: "This might take some time depending on your connectivity.",
|
info: 'This might take some time depending on your connectivity.',
|
||||||
startMessage: "Installing dependencies using npm...",
|
startMessage: 'Installing dependencies using npm...',
|
||||||
command: `npm`,
|
command: `npm`,
|
||||||
subCommand: "install",
|
subCommand: 'install',
|
||||||
error: `Install dependencies later with ${colorize(
|
error: `Install dependencies later with ${colorize(
|
||||||
"yellow",
|
'yellow',
|
||||||
"npm install"
|
'npm install'
|
||||||
)}`,
|
)}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prompt: "Would you like to initialize your git repository?",
|
prompt: 'Would you like to initialize your git repository?',
|
||||||
startMessage: "Initializing git repository...",
|
startMessage: 'Initializing git repository...',
|
||||||
command: `git`,
|
command: `git`,
|
||||||
subCommand: "init",
|
subCommand: 'init',
|
||||||
error: `Initialize git repository later with ${colorize(
|
error: `Initialize git repository later with ${colorize(
|
||||||
"yellow",
|
'yellow',
|
||||||
"git init"
|
'git init'
|
||||||
)}`,
|
)}`,
|
||||||
},
|
},
|
||||||
];
|
]
|
||||||
|
|
||||||
const intentions = await askPrompts(prompts, directory);
|
const intentions = await askPrompts(prompts, directory)
|
||||||
if (!!intentions && intentions.length > 0)
|
if (!!intentions && intentions.length > 0)
|
||||||
showResults(directory, intentions[0]);
|
showResults(directory, intentions[0])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,10 +86,10 @@ async function create() {
|
||||||
* @returns string | undefined
|
* @returns string | undefined
|
||||||
*/
|
*/
|
||||||
function getSafeDirectory(directory) {
|
function getSafeDirectory(directory) {
|
||||||
const { platform } = process;
|
const { platform } = process
|
||||||
const locale = path[platform === `win32` ? `win32` : `posix`];
|
const locale = path[platform === `win32` ? `win32` : `posix`]
|
||||||
const localePath = directory.split(path.sep).join(locale.sep);
|
const localePath = directory.split(path.sep).join(locale.sep)
|
||||||
return path.normalize(localePath);
|
return path.normalize(localePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -98,22 +98,22 @@ function getSafeDirectory(directory) {
|
||||||
* @returns Promise<boolean> hasErrors
|
* @returns Promise<boolean> hasErrors
|
||||||
*/
|
*/
|
||||||
async function downloadTemplateToDirectory(directory) {
|
async function downloadTemplateToDirectory(directory) {
|
||||||
let hasErrors = false;
|
let hasErrors = false
|
||||||
|
|
||||||
try {
|
try {
|
||||||
consola.start(
|
consola.start(
|
||||||
`Copying template to ${colorize("bold", getSafeDirectory(directory))}...`
|
`Copying template to ${colorize('bold', getSafeDirectory(directory))}...`
|
||||||
);
|
)
|
||||||
await downloadTemplate("github:ayoayco/mcfly/templates/basic", {
|
await downloadTemplate('github:ayoayco/mcfly/templates/basic', {
|
||||||
dir: directory,
|
dir: directory,
|
||||||
});
|
})
|
||||||
} catch (ㆆ_ㆆ) {
|
} catch (ㆆ_ㆆ) {
|
||||||
consola.error(ㆆ_ㆆ.message);
|
consola.error(ㆆ_ㆆ.message)
|
||||||
consola.info("Try a different name.\n");
|
consola.info('Try a different name.\n')
|
||||||
hasErrors = true;
|
hasErrors = true
|
||||||
}
|
}
|
||||||
|
|
||||||
return hasErrors;
|
return hasErrors
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -123,37 +123,37 @@ async function downloadTemplateToDirectory(directory) {
|
||||||
* @returns Array<boolean> | undefined
|
* @returns Array<boolean> | undefined
|
||||||
*/
|
*/
|
||||||
async function askPrompts(prompts, cwd) {
|
async function askPrompts(prompts, cwd) {
|
||||||
const results = [];
|
const results = []
|
||||||
|
|
||||||
for (const p of prompts) {
|
for (const p of prompts) {
|
||||||
const userIntends = await consola.prompt(p.prompt, {
|
const userIntends = await consola.prompt(p.prompt, {
|
||||||
type: "confirm",
|
type: 'confirm',
|
||||||
});
|
})
|
||||||
|
|
||||||
if (typeof userIntends !== "boolean") {
|
if (typeof userIntends !== 'boolean') {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (userIntends) {
|
if (userIntends) {
|
||||||
p.info && consola.info(p.info);
|
p.info && consola.info(p.info)
|
||||||
consola.start(p.startMessage);
|
consola.start(p.startMessage)
|
||||||
try {
|
try {
|
||||||
spawnSync(p.command, [p.subCommand], {
|
spawnSync(p.command, [p.subCommand], {
|
||||||
cwd,
|
cwd,
|
||||||
shell: true,
|
shell: true,
|
||||||
timeout: 100_000,
|
timeout: 100_000,
|
||||||
stdio: "inherit",
|
stdio: 'inherit',
|
||||||
});
|
})
|
||||||
consola.success("Done!");
|
consola.success('Done!')
|
||||||
} catch (ㆆ_ㆆ) {
|
} catch (ㆆ_ㆆ) {
|
||||||
consola.error(ㆆ_ㆆ.message);
|
consola.error(ㆆ_ㆆ.message)
|
||||||
consola.info(p.error + "\n");
|
consola.info(p.error + '\n')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
results.push(userIntends);
|
results.push(userIntends)
|
||||||
}
|
}
|
||||||
|
|
||||||
return results;
|
return results
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -163,28 +163,28 @@ async function askPrompts(prompts, cwd) {
|
||||||
*/
|
*/
|
||||||
function showResults(directory, installDeps) {
|
function showResults(directory, installDeps) {
|
||||||
let nextActions = [
|
let nextActions = [
|
||||||
`Go to your project by running ${colorize("yellow", `cd ${directory}`)}`,
|
`Go to your project by running ${colorize('yellow', `cd ${directory}`)}`,
|
||||||
];
|
]
|
||||||
|
|
||||||
if (!installDeps) {
|
if (!installDeps) {
|
||||||
nextActions.push(
|
nextActions.push(
|
||||||
`Install the dependencies with ${colorize("yellow", "npm install")}`
|
`Install the dependencies with ${colorize('yellow', 'npm install')}`
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
nextActions = nextActions.concat([
|
nextActions = nextActions.concat([
|
||||||
`Start the dev server with ${colorize("yellow", "npm start")}`,
|
`Start the dev server with ${colorize('yellow', 'npm start')}`,
|
||||||
`Join us at ${colorize("blue", "https://ayco.io/gh/McFly")}`,
|
`Join us at ${colorize('blue', 'https://ayco.io/gh/McFly')}`,
|
||||||
]);
|
])
|
||||||
|
|
||||||
const result = `🎉 Your new ${colorize(
|
const result = `🎉 Your new ${colorize(
|
||||||
"bold",
|
'bold',
|
||||||
"McFly"
|
'McFly'
|
||||||
)} app is ready: ${directory}\n\nNext actions: ${nextActions
|
)} app is ready: ${directory}\n\nNext actions: ${nextActions
|
||||||
.map((action, index) => `\n${++index}. ${action}`)
|
.map((action, index) => `\n${++index}. ${action}`)
|
||||||
.join("")}`;
|
.join('')}`
|
||||||
|
|
||||||
consola.box(result);
|
consola.box(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
create();
|
create()
|
||||||
|
|
|
@ -5,10 +5,10 @@
|
||||||
* @type {import("prettier").Config}
|
* @type {import("prettier").Config}
|
||||||
*/
|
*/
|
||||||
const config = {
|
const config = {
|
||||||
trailingComma: "es5",
|
trailingComma: 'es5',
|
||||||
tabWidth: 2,
|
tabWidth: 2,
|
||||||
semi: false,
|
semi: false,
|
||||||
singleQuote: true,
|
singleQuote: true,
|
||||||
};
|
}
|
||||||
|
|
||||||
export default config;
|
export default config
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { defineMcFlyConfig } from "#imports";
|
import { defineMcFlyConfig } from '#imports'
|
||||||
export default defineMcFlyConfig({
|
export default defineMcFlyConfig({
|
||||||
components: "js",
|
components: 'js',
|
||||||
});
|
})
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
export default defineNitroConfig({
|
export default defineNitroConfig({
|
||||||
extends: "@mcflyjs/config",
|
extends: '@mcflyjs/config',
|
||||||
|
|
||||||
devServer: {
|
devServer: {
|
||||||
watch: ["../packages"],
|
watch: ['../packages'],
|
||||||
},
|
},
|
||||||
|
|
||||||
routeRules: {
|
routeRules: {
|
||||||
"/chat": {
|
'/chat': {
|
||||||
redirect: {
|
redirect: {
|
||||||
to: "https://matrix.to/#/#mcfly:matrix.org",
|
to: 'https://matrix.to/#/#mcfly:matrix.org',
|
||||||
statusCode: 302,
|
statusCode: 302,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -19,5 +19,5 @@ export default defineNitroConfig({
|
||||||
brotli: true,
|
brotli: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
compatibilityDate: "2024-12-08",
|
compatibilityDate: '2024-12-08',
|
||||||
});
|
})
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -5,5 +5,5 @@
|
||||||
* ...reusable code are in ./src/components
|
* ...reusable code are in ./src/components
|
||||||
* @see https://ayco.io/gh/McFly#special-directories
|
* @see https://ayco.io/gh/McFly#special-directories
|
||||||
*/
|
*/
|
||||||
import config from "../mcfly.config.mjs";
|
import config from '../mcfly.config.mjs'
|
||||||
export default useMcFlyRoute({ config, storage: useStorage() });
|
export default useMcFlyRoute({ config, storage: useStorage() })
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
*/
|
*/
|
||||||
class ClickableText extends WebComponent {
|
class ClickableText extends WebComponent {
|
||||||
onInit() {
|
onInit() {
|
||||||
this.onclick = () => alert("Thank you for clicking the text!");
|
this.onclick = () => alert('Thank you for clicking the text!')
|
||||||
}
|
}
|
||||||
get template() {
|
get template() {
|
||||||
return `<span style="cursor:pointer">Click me too!</span>`;
|
return `<span style="cursor:pointer">Click me too!</span>`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,41 +1,41 @@
|
||||||
class CodeBlockComponent extends HTMLElement {
|
class CodeBlockComponent extends HTMLElement {
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
const trimmed = this.innerHTML.trim();
|
const trimmed = this.innerHTML.trim()
|
||||||
const lang = this.getAttribute("language");
|
const lang = this.getAttribute('language')
|
||||||
const inline = this.getAttribute("inline") !== null;
|
const inline = this.getAttribute('inline') !== null
|
||||||
|
|
||||||
this.innerHTML = `
|
this.innerHTML = `
|
||||||
<pre id="pre"><code id="code">${trimmed}</code></pre>
|
<pre id="pre"><code id="code">${trimmed}</code></pre>
|
||||||
`;
|
`
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {HTMLPreElement}
|
* @type {HTMLPreElement}
|
||||||
*/
|
*/
|
||||||
const pre = this.querySelector("#pre");
|
const pre = this.querySelector('#pre')
|
||||||
|
|
||||||
if (lang) {
|
if (lang) {
|
||||||
pre.className = `language-${lang}`;
|
pre.className = `language-${lang}`
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {Partial<CSSStyleDeclaration>}
|
* @type {Partial<CSSStyleDeclaration>}
|
||||||
*/
|
*/
|
||||||
const style = {
|
const style = {
|
||||||
background: "#f5f2f0",
|
background: '#f5f2f0',
|
||||||
padding: "1em",
|
padding: '1em',
|
||||||
margin: "1em 0",
|
margin: '1em 0',
|
||||||
fontSize: "large",
|
fontSize: 'large',
|
||||||
overflow: "auto",
|
overflow: 'auto',
|
||||||
borderRadius: '5px'
|
borderRadius: '5px',
|
||||||
};
|
}
|
||||||
|
|
||||||
if (inline) {
|
if (inline) {
|
||||||
style.display = 'inline';
|
style.display = 'inline'
|
||||||
style.padding = '0.3em';
|
style.padding = '0.3em'
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.keys(style).forEach((rule) => {
|
Object.keys(style).forEach((rule) => {
|
||||||
pre.style[rule] = style[rule];
|
pre.style[rule] = style[rule]
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,14 +8,16 @@ class HelloWorld extends WebComponent {
|
||||||
count: 0,
|
count: 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
updateLabel(){
|
updateLabel() {
|
||||||
this.props.myName = `Clicked ${++this.props.count}x`;
|
this.props.myName = `Clicked ${++this.props.count}x`
|
||||||
}
|
}
|
||||||
|
|
||||||
get template() {
|
get template() {
|
||||||
return html`
|
return html` <button
|
||||||
<button onClick=${() => this.updateLabel()} style="cursor:pointer">
|
onClick=${() => this.updateLabel()}
|
||||||
|
style="cursor:pointer"
|
||||||
|
>
|
||||||
Hello ${this.props.myName}!
|
Hello ${this.props.myName}!
|
||||||
</button>`;
|
</button>`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
class HelloWorld extends HTMLElement {
|
class HelloWorld extends HTMLElement {
|
||||||
static get observedAttributes() {
|
static get observedAttributes() {
|
||||||
return ["my-name"];
|
return ['my-name']
|
||||||
}
|
}
|
||||||
|
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
let count = 0;
|
let count = 0
|
||||||
const currentName = this.getAttribute('my-name');
|
const currentName = this.getAttribute('my-name')
|
||||||
|
|
||||||
if (!currentName) {
|
if (!currentName) {
|
||||||
this.setAttribute('my-name', 'World')
|
this.setAttribute('my-name', 'World')
|
||||||
}
|
}
|
||||||
|
|
||||||
this.onclick = () => this.setAttribute("my-name", `Clicked ${++count}x`);
|
this.onclick = () => this.setAttribute('my-name', `Clicked ${++count}x`)
|
||||||
}
|
}
|
||||||
|
|
||||||
attributeChangedCallback(property, previousValue, currentValue) {
|
attributeChangedCallback(property, previousValue, currentValue) {
|
||||||
if (property === "my-name" && previousValue !== currentValue) {
|
if (property === 'my-name' && previousValue !== currentValue) {
|
||||||
this.innerHTML = `<button style="cursor:pointer">Hello ${currentValue}!</button>`;
|
this.innerHTML = `<button style="cursor:pointer">Hello ${currentValue}!</button>`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { defineMcFlyConfig } from "#imports";
|
import { defineMcFlyConfig } from '#imports'
|
||||||
export default defineMcFlyConfig({
|
export default defineMcFlyConfig({
|
||||||
components: "js",
|
components: 'js',
|
||||||
});
|
})
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
export default defineNitroConfig({ extends: '@mcflyjs/config' });
|
export default defineNitroConfig({ extends: '@mcflyjs/config' })
|
||||||
|
|
|
@ -5,5 +5,5 @@
|
||||||
* ...reusable code are in ./src/components
|
* ...reusable code are in ./src/components
|
||||||
* @see https://ayco.io/gh/McFly#special-directories
|
* @see https://ayco.io/gh/McFly#special-directories
|
||||||
*/
|
*/
|
||||||
import config from "../mcfly.config.mjs";
|
import config from '../mcfly.config.mjs'
|
||||||
export default useMcFlyRoute({ config, storage: useStorage() });
|
export default useMcFlyRoute({ config, storage: useStorage() })
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
*/
|
*/
|
||||||
export default eventHandler(() => {
|
export default eventHandler(() => {
|
||||||
return {
|
return {
|
||||||
user: "AYO",
|
user: 'AYO',
|
||||||
date: new Date(),
|
date: new Date(),
|
||||||
};
|
}
|
||||||
});
|
})
|
||||||
|
|
|
@ -1,41 +1,41 @@
|
||||||
class CodeBlockComponent extends HTMLElement {
|
class CodeBlockComponent extends HTMLElement {
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
const trimmed = this.innerHTML.trim();
|
const trimmed = this.innerHTML.trim()
|
||||||
const lang = this.getAttribute("language");
|
const lang = this.getAttribute('language')
|
||||||
const inline = this.getAttribute("inline") !== null;
|
const inline = this.getAttribute('inline') !== null
|
||||||
|
|
||||||
this.innerHTML = `
|
this.innerHTML = `
|
||||||
<pre id="pre"><code id="code">${trimmed}</code></pre>
|
<pre id="pre"><code id="code">${trimmed}</code></pre>
|
||||||
`;
|
`
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {HTMLPreElement}
|
* @type {HTMLPreElement}
|
||||||
*/
|
*/
|
||||||
const pre = this.querySelector("#pre");
|
const pre = this.querySelector('#pre')
|
||||||
|
|
||||||
if (lang) {
|
if (lang) {
|
||||||
pre.className = `language-${lang}`;
|
pre.className = `language-${lang}`
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {Partial<CSSStyleDeclaration>}
|
* @type {Partial<CSSStyleDeclaration>}
|
||||||
*/
|
*/
|
||||||
const style = {
|
const style = {
|
||||||
background: "#f5f2f0",
|
background: '#f5f2f0',
|
||||||
padding: "1em",
|
padding: '1em',
|
||||||
margin: "1em 0",
|
margin: '1em 0',
|
||||||
fontSize: "large",
|
fontSize: 'large',
|
||||||
overflow: "auto",
|
overflow: 'auto',
|
||||||
borderRadius: '5px'
|
borderRadius: '5px',
|
||||||
};
|
}
|
||||||
|
|
||||||
if (inline) {
|
if (inline) {
|
||||||
style.display = 'inline';
|
style.display = 'inline'
|
||||||
style.padding = '0.3em';
|
style.padding = '0.3em'
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.keys(style).forEach((rule) => {
|
Object.keys(style).forEach((rule) => {
|
||||||
pre.style[rule] = style[rule];
|
pre.style[rule] = style[rule]
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
class MyHelloWorld extends WebComponent {
|
class MyHelloWorld extends WebComponent {
|
||||||
static props = {
|
static props = {
|
||||||
myName: 'World',
|
myName: 'World',
|
||||||
count: 0
|
count: 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
updateLabel() {
|
updateLabel() {
|
||||||
|
@ -13,9 +13,11 @@ class MyHelloWorld extends WebComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
get template() {
|
get template() {
|
||||||
return html`
|
return html` <button
|
||||||
<button onClick=${() => this.updateLabel()} style="cursor:pointer">
|
onClick=${() => this.updateLabel()}
|
||||||
|
style="cursor:pointer"
|
||||||
|
>
|
||||||
Hello ${this.props.myName}!
|
Hello ${this.props.myName}!
|
||||||
</button>`;
|
</button>`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue