Update various configuration files, components, and assets; enhance notification system and API endpoints; improve documentation and styles across the application.
This commit is contained in:
48
server/api/devtool/content/canvas/file-code.js
Normal file
48
server/api/devtool/content/canvas/file-code.js
Normal file
@@ -0,0 +1,48 @@
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const query = await getQuery(event);
|
||||
|
||||
let code = "";
|
||||
// console.log(query.path);
|
||||
|
||||
try {
|
||||
// Get vue code from path in query
|
||||
const filePath = path.join(process.cwd() + "/pages/", query.path + ".vue");
|
||||
try {
|
||||
code = fs.readFileSync(filePath, "utf8");
|
||||
return {
|
||||
statusCode: 200,
|
||||
message: "Code successfully loaded",
|
||||
data: code,
|
||||
};
|
||||
} catch (error) {}
|
||||
|
||||
// Check if there is path with index.vue
|
||||
const filePathIndex = path.join(
|
||||
process.cwd() + "/pages/",
|
||||
query.path + "/index.vue"
|
||||
);
|
||||
|
||||
code = fs.readFileSync(filePathIndex, "utf8");
|
||||
|
||||
// Only get the template part of the code and make sure its from the first template tag to the last template tag
|
||||
code = code.substring(
|
||||
code.indexOf("<template>") + 10,
|
||||
code.lastIndexOf("</template>")
|
||||
);
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
message: "Code successfully loaded",
|
||||
data: code,
|
||||
mode: "index",
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
statusCode: 500,
|
||||
message: "File not found",
|
||||
};
|
||||
}
|
||||
});
|
||||
42
server/api/devtool/content/code/file-code.js
Normal file
42
server/api/devtool/content/code/file-code.js
Normal file
@@ -0,0 +1,42 @@
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const query = await getQuery(event);
|
||||
|
||||
let code = "";
|
||||
// console.log(query.path);
|
||||
|
||||
try {
|
||||
// Get vue code from path in query
|
||||
const filePath = path.join(process.cwd() + "/pages/", query.path + ".vue");
|
||||
try {
|
||||
code = fs.readFileSync(filePath, "utf8");
|
||||
return {
|
||||
statusCode: 200,
|
||||
message: "Code successfully loaded",
|
||||
data: code,
|
||||
};
|
||||
} catch (error) {}
|
||||
|
||||
// Check if there is path with index.vue
|
||||
const filePathIndex = path.join(
|
||||
process.cwd() + "/pages/",
|
||||
query.path + "/index.vue"
|
||||
);
|
||||
|
||||
code = fs.readFileSync(filePathIndex, "utf8");
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
message: "Code successfully loaded",
|
||||
data: code,
|
||||
mode: "index",
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
statusCode: 500,
|
||||
message: "File not found",
|
||||
};
|
||||
}
|
||||
});
|
||||
450
server/api/devtool/content/code/linter.js
Normal file
450
server/api/devtool/content/code/linter.js
Normal file
@@ -0,0 +1,450 @@
|
||||
import { ESLint } from "eslint";
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const body = await readBody(event);
|
||||
|
||||
try {
|
||||
if (body.code === undefined) {
|
||||
return {
|
||||
statusCode: 400,
|
||||
message: "Bad Request",
|
||||
};
|
||||
}
|
||||
|
||||
const code = body.code;
|
||||
|
||||
// Extract script and template content once
|
||||
const scriptContent =
|
||||
code.match(/<script\b[^>]*>([\s\S]*?)<\/script>/)?.[1] || "";
|
||||
const templateContent = code.match(/<template>([\s\S]*)<\/template>/)?.[1];
|
||||
|
||||
// Validate FormKit inputs
|
||||
const validateFormKit = (content) => {
|
||||
// List of valid FormKit input types
|
||||
const validFormKitTypes = [
|
||||
"text",
|
||||
"email",
|
||||
"url",
|
||||
"tel",
|
||||
"password",
|
||||
"number",
|
||||
"date",
|
||||
"datetime-local",
|
||||
"time",
|
||||
"month",
|
||||
"week",
|
||||
"search",
|
||||
"color",
|
||||
"file",
|
||||
"range",
|
||||
"checkbox",
|
||||
"radio",
|
||||
"select",
|
||||
"textarea",
|
||||
"submit",
|
||||
"button",
|
||||
"mask",
|
||||
"form",
|
||||
];
|
||||
|
||||
// Find all FormKit components
|
||||
const formKitRegex = /<FormKit[^>]*>/g;
|
||||
let formKitMatch;
|
||||
|
||||
// Start counting from template tag
|
||||
let lineNumber = content
|
||||
.slice(0, content.indexOf("<template"))
|
||||
.split("\n").length;
|
||||
let lastIndex = 0;
|
||||
|
||||
while ((formKitMatch = formKitRegex.exec(content)) !== null) {
|
||||
// Calculate correct line number including the lines before template
|
||||
lineNumber += (
|
||||
content.slice(lastIndex, formKitMatch.index).match(/\n/g) || []
|
||||
).length;
|
||||
lastIndex = formKitMatch.index;
|
||||
|
||||
const formKitTag = formKitMatch[0];
|
||||
|
||||
// Extract type attribute
|
||||
const typeMatch = formKitTag.match(/type=["']([^"']+)["']/);
|
||||
if (!typeMatch) {
|
||||
throw {
|
||||
message: "FormKit component missing required 'type' attribute",
|
||||
line: lineNumber,
|
||||
column:
|
||||
formKitMatch.index -
|
||||
content.lastIndexOf("\n", formKitMatch.index),
|
||||
};
|
||||
}
|
||||
|
||||
const inputType = typeMatch[1];
|
||||
if (!validFormKitTypes.includes(inputType)) {
|
||||
throw {
|
||||
message: `Invalid FormKit type: "${inputType}". Please use a valid input type.`,
|
||||
line: lineNumber,
|
||||
column:
|
||||
formKitMatch.index -
|
||||
content.lastIndexOf("\n", formKitMatch.index),
|
||||
};
|
||||
}
|
||||
|
||||
// Check for options in select, radio, and checkbox types
|
||||
if (["select", "radio", "checkbox"].includes(inputType)) {
|
||||
// Look for :options or v-model
|
||||
const hasOptions =
|
||||
formKitTag.includes(":options=") || formKitTag.includes("v-model=");
|
||||
const hasSlotContent =
|
||||
content
|
||||
.slice(
|
||||
formKitMatch.index,
|
||||
content.indexOf(">", formKitMatch.index)
|
||||
)
|
||||
.includes(">") &&
|
||||
content
|
||||
.slice(
|
||||
formKitMatch.index,
|
||||
content.indexOf("</FormKit>", formKitMatch.index)
|
||||
)
|
||||
.includes("<option");
|
||||
|
||||
if (!hasOptions && !hasSlotContent) {
|
||||
throw {
|
||||
message: `FormKit ${inputType} requires options. Add :options prop or option slots.`,
|
||||
line: lineNumber,
|
||||
column:
|
||||
formKitMatch.index -
|
||||
content.lastIndexOf("\n", formKitMatch.index),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Add new function to validate mustache syntax
|
||||
const validateMustacheSyntax = (content) => {
|
||||
const stack = [];
|
||||
let lineNumber = 1;
|
||||
let lastIndex = 0;
|
||||
|
||||
for (let i = 0; i < content.length; i++) {
|
||||
if (content[i] === "\n") {
|
||||
lineNumber++;
|
||||
lastIndex = i + 1;
|
||||
}
|
||||
|
||||
if (content[i] === "{" && content[i + 1] === "{") {
|
||||
stack.push({
|
||||
position: i,
|
||||
line: lineNumber,
|
||||
column: i - lastIndex,
|
||||
});
|
||||
i++; // Skip next '{'
|
||||
} else if (content[i] === "}" && content[i + 1] === "}") {
|
||||
if (stack.length === 0) {
|
||||
throw {
|
||||
message:
|
||||
"Unexpected closing mustache brackets '}}' without matching opening brackets",
|
||||
line: lineNumber,
|
||||
column: i - lastIndex,
|
||||
};
|
||||
}
|
||||
stack.pop();
|
||||
i++; // Skip next '}'
|
||||
}
|
||||
}
|
||||
|
||||
if (stack.length > 0) {
|
||||
const unclosed = stack[0];
|
||||
throw {
|
||||
message:
|
||||
"Unclosed mustache brackets '{{'. Missing closing brackets '}}",
|
||||
line: unclosed.line,
|
||||
column: unclosed.column,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
// Check template content and FormKit validation
|
||||
if (templateContent) {
|
||||
try {
|
||||
validateMustacheSyntax(templateContent);
|
||||
validateFormKit(templateContent);
|
||||
} catch (error) {
|
||||
return {
|
||||
statusCode: 400,
|
||||
message: "Template Syntax Error",
|
||||
data: {
|
||||
message: error.message,
|
||||
line: error.line,
|
||||
column: error.column,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// Check for undefined variables
|
||||
const definedVariables = new Set();
|
||||
|
||||
// Add common Vue variables
|
||||
const commonVueVars = [
|
||||
"$route",
|
||||
"$router",
|
||||
"$refs",
|
||||
"$emit",
|
||||
"$slots",
|
||||
"$attrs",
|
||||
];
|
||||
commonVueVars.forEach((v) => definedVariables.add(v));
|
||||
|
||||
// Extract refs and other variables from script
|
||||
const refRegex = /(?:const|let|var)\s+(\w+)\s*=/g;
|
||||
let varMatch;
|
||||
while ((varMatch = refRegex.exec(scriptContent)) !== null) {
|
||||
definedVariables.add(varMatch[1]);
|
||||
}
|
||||
|
||||
// Extract defineProps if any
|
||||
const propsMatch = scriptContent.match(/defineProps\(\s*{([^}]+)}\s*\)/);
|
||||
if (propsMatch) {
|
||||
const propsContent = propsMatch[1];
|
||||
const propNames = propsContent.match(/(\w+)\s*:/g);
|
||||
propNames?.forEach((prop) => {
|
||||
definedVariables.add(prop.replace(":", "").trim());
|
||||
});
|
||||
}
|
||||
|
||||
// Check template for undefined variables
|
||||
const mustacheRegex = /{{([^}]+)}}/g;
|
||||
let lineNumber = 1;
|
||||
let lastIndex = 0;
|
||||
let mustacheMatch;
|
||||
|
||||
while ((mustacheMatch = mustacheRegex.exec(templateContent)) !== null) {
|
||||
// Calculate line number
|
||||
lineNumber += (
|
||||
templateContent.slice(lastIndex, mustacheMatch.index).match(/\n/g) ||
|
||||
[]
|
||||
).length;
|
||||
lastIndex = mustacheMatch.index;
|
||||
|
||||
const expression = mustacheMatch[1].trim();
|
||||
// Split expression and check each variable
|
||||
const variables = expression.split(/[\s.()[\]]+/);
|
||||
|
||||
for (const variable of variables) {
|
||||
// Skip numbers, operators, and empty strings
|
||||
if (
|
||||
!variable ||
|
||||
variable.match(/^[\d+\-*/&|!%<>=?:]+$/) ||
|
||||
variable === "true" ||
|
||||
variable === "false"
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!definedVariables.has(variable)) {
|
||||
return {
|
||||
statusCode: 400,
|
||||
message: "Template Reference Error",
|
||||
data: {
|
||||
message: `Variable "${variable}" is not defined`,
|
||||
line: lineNumber,
|
||||
column:
|
||||
mustacheMatch.index -
|
||||
templateContent.lastIndexOf("\n", mustacheMatch.index),
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Validate template structure
|
||||
const validateTemplateStructure = (code) => {
|
||||
// Add new validation for script tags inside template
|
||||
const templateContent1 = code.match(
|
||||
/<template>([\s\S]*)<\/template>/
|
||||
)?.[1];
|
||||
if (templateContent1) {
|
||||
const scriptInTemplate = templateContent1.match(/<script\b[^>]*>/i);
|
||||
if (scriptInTemplate) {
|
||||
const lineNumber = templateContent1
|
||||
.slice(0, scriptInTemplate.index)
|
||||
.split("\n").length;
|
||||
const column =
|
||||
scriptInTemplate.index -
|
||||
templateContent1.lastIndexOf("\n", scriptInTemplate.index);
|
||||
|
||||
throw {
|
||||
message: "Script tags are not allowed inside template section",
|
||||
line: lineNumber,
|
||||
column: column,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Check for root level template and script tags
|
||||
const rootTemplateCount = (
|
||||
code.match(/^[\s\S]*<template>[\s\S]*<\/template>/g) || []
|
||||
).length;
|
||||
const rootScriptCount = (
|
||||
code.match(/^[\s\S]*<script>[\s\S]*<\/script>/g) || []
|
||||
).length;
|
||||
|
||||
if (rootTemplateCount > 1 || rootScriptCount > 1) {
|
||||
throw new Error(
|
||||
"Vue components must have only one root <template> and one <script> tag"
|
||||
);
|
||||
}
|
||||
|
||||
// Extract template content for further validation
|
||||
const templateContent2 = code.match(
|
||||
/<template>([\s\S]*)<\/template>/
|
||||
)?.[1];
|
||||
if (templateContent2) {
|
||||
const tagStack = [];
|
||||
const tagRegex = /<\/?([a-zA-Z][a-zA-Z0-9:-]*)\s*([^>]*?)(\/?)>/g;
|
||||
let match;
|
||||
let lineNumber = 1;
|
||||
let lastIndex = 0;
|
||||
|
||||
while ((match = tagRegex.exec(templateContent2)) !== null) {
|
||||
const [fullTag, tagName, attributes, selfClosing] = match;
|
||||
|
||||
// Calculate line number
|
||||
lineNumber += (
|
||||
templateContent2.slice(lastIndex, match.index).match(/\n/g) || []
|
||||
).length;
|
||||
lastIndex = match.index;
|
||||
|
||||
// Skip comments
|
||||
if (templateContent2.slice(match.index).startsWith("<!--")) {
|
||||
const commentEnd = templateContent2.indexOf("-->", match.index);
|
||||
if (commentEnd !== -1) {
|
||||
tagRegex.lastIndex = commentEnd + 3;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!fullTag.endsWith(">")) {
|
||||
throw {
|
||||
message: `Malformed tag found: ${fullTag}`,
|
||||
line: lineNumber,
|
||||
column:
|
||||
match.index - templateContent2.lastIndexOf("\n", match.index),
|
||||
};
|
||||
}
|
||||
|
||||
if (selfClosing || fullTag.endsWith("/>")) continue;
|
||||
|
||||
if (!fullTag.startsWith("</")) {
|
||||
tagStack.push({
|
||||
name: tagName,
|
||||
line: lineNumber,
|
||||
column:
|
||||
match.index - templateContent2.lastIndexOf("\n", match.index),
|
||||
});
|
||||
} else {
|
||||
if (tagStack.length === 0) {
|
||||
throw {
|
||||
message: `Unexpected closing tag </${tagName}> found without matching opening tag`,
|
||||
line: lineNumber,
|
||||
column:
|
||||
match.index - templateContent2.lastIndexOf("\n", match.index),
|
||||
};
|
||||
}
|
||||
|
||||
const lastTag = tagStack[tagStack.length - 1];
|
||||
if (lastTag.name !== tagName) {
|
||||
throw {
|
||||
message: `Mismatched tags: expected closing tag for "${lastTag.name}" but found "${tagName}"`,
|
||||
line: lineNumber,
|
||||
column:
|
||||
match.index - templateContent2.lastIndexOf("\n", match.index),
|
||||
};
|
||||
}
|
||||
tagStack.pop();
|
||||
}
|
||||
}
|
||||
|
||||
if (tagStack.length > 0) {
|
||||
const unclosedTag = tagStack[tagStack.length - 1];
|
||||
throw {
|
||||
message: `Unclosed tag: ${unclosedTag.name}`,
|
||||
line: unclosedTag.line,
|
||||
column: unclosedTag.column,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
try {
|
||||
validateTemplateStructure(code);
|
||||
} catch (structureError) {
|
||||
return {
|
||||
statusCode: 400,
|
||||
message: "Template Structure Error",
|
||||
data: {
|
||||
message: structureError.message,
|
||||
line: structureError.line || 1,
|
||||
column: structureError.column || 0,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// ESLint configuration
|
||||
const eslint = new ESLint({
|
||||
overrideConfig: {
|
||||
extends: ["plugin:vue/vue3-recommended"],
|
||||
parserOptions: {
|
||||
parser: "espree",
|
||||
ecmaVersion: 2022,
|
||||
sourceType: "module",
|
||||
},
|
||||
},
|
||||
useEslintrc: false,
|
||||
});
|
||||
|
||||
const results = await eslint.lintText(code);
|
||||
|
||||
if (results[0].messages.length > 0) {
|
||||
const message = results[0].messages[0];
|
||||
|
||||
if (message.fatal === true) {
|
||||
return {
|
||||
statusCode: 400,
|
||||
message: "Bad Linter Test",
|
||||
data: {
|
||||
message: message.message,
|
||||
line: message.line,
|
||||
column: message.column,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
message: "Good Linter test",
|
||||
data: {
|
||||
message: message.message,
|
||||
line: message.line,
|
||||
column: message.column,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
message: "Code validation passed",
|
||||
};
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
return {
|
||||
statusCode: 500,
|
||||
message: "Internal Server Error",
|
||||
error: error.message,
|
||||
};
|
||||
}
|
||||
});
|
||||
27
server/api/devtool/content/code/prettier-format.js
Normal file
27
server/api/devtool/content/code/prettier-format.js
Normal file
@@ -0,0 +1,27 @@
|
||||
import prettier from "prettier";
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const body = await readBody(event);
|
||||
|
||||
try {
|
||||
if (body.code === undefined) {
|
||||
return {
|
||||
statusCode: 400,
|
||||
message: "Bad Request",
|
||||
};
|
||||
}
|
||||
|
||||
const code = prettier.format(body.code, { semi: false, parser: "vue" });
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
message: "Code successfully formatted",
|
||||
data: code,
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
statusCode: 500,
|
||||
message: "Internal Server Error",
|
||||
};
|
||||
}
|
||||
});
|
||||
22
server/api/devtool/content/code/save.js
Normal file
22
server/api/devtool/content/code/save.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const body = await readBody(event);
|
||||
|
||||
try {
|
||||
// Overwrite vue code from path in body with new code
|
||||
const filePath = path.join(process.cwd() + "/pages/", body.path + ".vue");
|
||||
fs.writeFileSync(filePath, body.code, "utf8");
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
message: "Code successfully saved",
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
statusCode: 500,
|
||||
message: "Internal Server Error",
|
||||
};
|
||||
}
|
||||
});
|
||||
29
server/api/devtool/content/template/get-list.js
Normal file
29
server/api/devtool/content/template/get-list.js
Normal file
@@ -0,0 +1,29 @@
|
||||
import templates from "@@/templates/index.js";
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
try {
|
||||
const query = await getQuery(event);
|
||||
const id = query.id;
|
||||
|
||||
if (!templates || templates?.data.length == 0)
|
||||
return {
|
||||
statusCode: 404,
|
||||
message: "Template data not found",
|
||||
};
|
||||
|
||||
// Search template by id
|
||||
const template = templates.data.find((item) => item.id == id);
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
message: "Template data successfully fetched",
|
||||
data: template,
|
||||
};
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
return {
|
||||
statusCode: 500,
|
||||
message: "Internal server error",
|
||||
};
|
||||
}
|
||||
});
|
||||
57
server/api/devtool/content/template/import.js
Normal file
57
server/api/devtool/content/template/import.js
Normal file
@@ -0,0 +1,57 @@
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
|
||||
import templates from "@@/templates/index.js";
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
try {
|
||||
const query = await getQuery(event);
|
||||
const pagePath = query.path;
|
||||
const templateId = query.templateId;
|
||||
|
||||
// Get pageName path and check if it exists
|
||||
const filePath = path.join(process.cwd() + "/pages/", pagePath + ".vue");
|
||||
console.log(filePath);
|
||||
if (!fs.existsSync(filePath)) {
|
||||
return {
|
||||
statusCode: 500,
|
||||
message: "File path not found",
|
||||
};
|
||||
}
|
||||
|
||||
// Get template id from templates
|
||||
const template = templates.data.find(
|
||||
(template) => template.id === templateId
|
||||
);
|
||||
|
||||
// Get template path and check if it exists
|
||||
const templatePath = path.join(
|
||||
process.cwd() + "/templates/",
|
||||
template.filename + ".vue"
|
||||
);
|
||||
|
||||
if (!fs.existsSync(templatePath)) {
|
||||
return {
|
||||
statusCode: 500,
|
||||
message: "Template not found",
|
||||
};
|
||||
}
|
||||
|
||||
// Get template code
|
||||
const templateCode = fs.readFileSync(templatePath, "utf8");
|
||||
|
||||
// Write template code to pageName path
|
||||
fs.writeFileSync(filePath, templateCode, "utf8");
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
message: "Template successfully imported",
|
||||
};
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
return {
|
||||
statusCode: 500,
|
||||
message: "Internal server error",
|
||||
};
|
||||
}
|
||||
});
|
||||
23
server/api/devtool/content/template/list.js
Normal file
23
server/api/devtool/content/template/list.js
Normal file
@@ -0,0 +1,23 @@
|
||||
import templates from "@@/templates/index.js";
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
try {
|
||||
if (!templates || templates?.data.length == 0)
|
||||
return {
|
||||
statusCode: 404,
|
||||
message: "Template data not found",
|
||||
};
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
message: "List template data successfully fetched",
|
||||
data: templates.data,
|
||||
};
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
return {
|
||||
statusCode: 500,
|
||||
message: "Internal server error",
|
||||
};
|
||||
}
|
||||
});
|
||||
23
server/api/devtool/content/template/tag.js
Normal file
23
server/api/devtool/content/template/tag.js
Normal file
@@ -0,0 +1,23 @@
|
||||
import templates from "@@/templates/index.js";
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
try {
|
||||
if (!templates || templates?.tags.length == 0)
|
||||
return {
|
||||
statusCode: 404,
|
||||
message: "Template tags not found",
|
||||
};
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
message: "List template tags successfully fetched",
|
||||
data: templates.tags,
|
||||
};
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
return {
|
||||
statusCode: 500,
|
||||
message: "Internal server error",
|
||||
};
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user