refactor(core): strictly type

This commit is contained in:
Ayo 2023-10-24 20:47:26 +02:00
parent 0124a9249f
commit e66ce3bbc5
2 changed files with 64 additions and 17 deletions

View file

@ -1,3 +1,16 @@
// @ts-check
/**
* @typedef {{
* components: 'js'
* }} McFlyConfig
*/
/**
* Define the configuration for the McFly project
* @param {McFlyConfig} config
* @returns {function(): McFlyConfig}
*/
export default function defineConfig(config) { export default function defineConfig(config) {
return () => config; return () => config;
} }

View file

@ -1,9 +1,23 @@
// @ts-check // @ts-check
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.mjs').McFlyConfig} McFlyConfig
* @typedef {import('unstorage').Storage} Storage
* @typedef {import('ultrahtml').Node} HtmlNode
* @typedef {import('estree').BaseNode} JsNode
*/
/**
* Intercepts all routes and assembles the correct HTML to return
* @param {{
* config: function(): McFlyConfig,
* storage: Storage
* }} param0
* @returns
*/
export function defineRoute({ config, storage }) { export function defineRoute({ config, storage }) {
return eventHandler(async (event) => { return eventHandler(async (event) => {
const { path } = event; const { path } = event;
@ -34,7 +48,13 @@ export function defineRoute({ config, storage }) {
}); });
} }
const getHtml = async (path, storage) => { /**
* Gets the correct HTML depending on the path requested
* @param {string} path
* @param {Storage} storage
* @returns
*/
async function getHtml(path, storage) {
const rawPath = path[path.length - 1] === "/" ? path.slice(0, -1) : path; const rawPath = path[path.length - 1] === "/" ? path.slice(0, -1) : path;
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");
@ -44,21 +64,22 @@ const getHtml = async (path, storage) => {
if (!html) html = await storage.getItem(getPath("/404.html")); if (!html) html = await storage.getItem(getPath("/404.html"));
return html; return html;
}; }
/** /**
* * Gets the storage path for a file
* @param {string} filename * @param {string} filename
* @returns string * @returns string
*/ */
function getPath(filename) { function getPath(filename) {
return `assets/pages${filename}`; return `assets:pages${filename}`;
} }
/** /**
* * Returns transformed HTML with custom elements registry in the head
* @param {string} html * @param {string} html
* @param {"js" | "ts"} type * @param {'js'} type
* @param {Storage} storage
* @returns Promise<string> * @returns Promise<string>
*/ */
async function insertRegistry(html, type, storage) { async function insertRegistry(html, type, storage) {
@ -96,10 +117,11 @@ async function insertRegistry(html, type, storage) {
} }
/** /**
* * Builds the string containing all custom elements definition
* @param {Array<string>} usedCustomElements * @param {Array<string>} usedCustomElements
* @param {"js" | "ts"} type * @param {"js" | "ts"} type
* @returns * @param {Storage} storage
* @returns string
*/ */
async function buildRegistry(usedCustomElements, type, storage) { async function buildRegistry(usedCustomElements, type, storage) {
let registryScript = `<script type='module'>`; let registryScript = `<script type='module'>`;
@ -138,7 +160,7 @@ async function buildRegistry(usedCustomElements, type, storage) {
} }
/** /**
* * Evaluates server:setup script and replaces all variables used in the HTML
* @param {string} html * @param {string} html
* @returns string * @returns string
*/ */
@ -174,7 +196,7 @@ function doSetUp(html) {
}); });
const regex = /{{(.*?)}}/g; const regex = /{{(.*?)}}/g;
var match; let match;
while ((match = regex.exec(html))) { while ((match = regex.exec(html))) {
let [key, value] = match; let [key, value] = match;
@ -186,7 +208,7 @@ function doSetUp(html) {
} }
/** /**
* * Removes any instance of server:setup script in the HTML
* @param {string} html * @param {string} html
* @returns string * @returns string
*/ */
@ -205,7 +227,7 @@ function deleteServerScripts(html) {
} }
/** /**
* * Cleans a JS string for save evaluation
* @param {Array<string>} scripts * @param {Array<string>} scripts
* @returns string * @returns string
*/ */
@ -218,7 +240,8 @@ function cleanScript(scripts) {
} }
/** /**
* * Checks if given node of a JS script is a comment
* @param {JsNode} node
* @returns boolean * @returns boolean
*/ */
function isComment(node) { function isComment(node) {
@ -231,7 +254,7 @@ function isComment(node) {
} }
/** /**
* * Removes all instances of comments in a JS string
* @param {string} script * @param {string} script
* @returns string * @returns string
*/ */
@ -253,12 +276,14 @@ function removeComments(script) {
.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;
} }
/** /**
* * Return HTML with all fragments replaced with the correct content in the storage
* @param {string} html * @param {string} html
* @param {Storage} storage
* @returns Promise<string> * @returns Promise<string>
*/ */
async function useFragments(html, storage) { async function useFragments(html, storage) {
@ -288,6 +313,9 @@ async function useFragments(html, storage) {
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}
*/
const fragmentNode = parse(availableFragments[selector]); const fragmentNode = parse(availableFragments[selector]);
replaceSlots(fragmentNode, node); replaceSlots(fragmentNode, node);
@ -299,6 +327,11 @@ async function useFragments(html, storage) {
return render(ast); return render(ast);
} }
/**
* Replace a slot in a fragmentNode with given node
* @param {HtmlNode} fragmentNode
* @param {HtmlNode} node
*/
function replaceSlots(fragmentNode, node) { function replaceSlots(fragmentNode, node) {
walkSync(fragmentNode, (n) => { walkSync(fragmentNode, (n) => {
if (n.type === ELEMENT_NODE && n.name === "slot") { if (n.type === ELEMENT_NODE && n.name === "slot") {
@ -309,8 +342,9 @@ function replaceSlots(fragmentNode, node) {
} }
/** /**
* * Get all files from the storage given a type
* @param {string} type * @param {string} type
* @param {Storage} storage
*/ */
async function getFiles(type, storage) { async function getFiles(type, storage) {
return (await storage.getKeys("assets:components")) return (await storage.getKeys("assets:components"))