diff --git a/lib/compiler/css.js b/lib/compiler/css.js index 7689f16..5fa7e28 100644 --- a/lib/compiler/css.js +++ b/lib/compiler/css.js @@ -12,7 +12,7 @@ export default { .split("\\n") .join("\\\n"); return [ - `const char *css_str_${identCount++} = "\\`, + `static const char *css_str_${identCount++} = "\\`, `${cssCode.substring(1, cssCode.length - 1)}\\`, '";\n', ].join("\n"); diff --git a/lib/compiler/index.js b/lib/compiler/index.js index c52ec47..b24177a 100644 --- a/lib/compiler/index.js +++ b/lib/compiler/index.js @@ -26,7 +26,13 @@ function compileFile(filePath, options) { let type = options.type; if (type === "auto") { - type = Object.keys(compilers).find((c) => compilers[c].test.test(filePath)); + type = Object.keys(compilers).find((c) => { + const { test } = compilers[c]; + if (test instanceof Function) { + return test(filePath); + } + return test.test(filePath); + }); } const compiler = compilers[type]; @@ -34,9 +40,10 @@ function compileFile(filePath, options) { return; } + console.log(`[lcui.${type}] compile ${filePath}`); const content = fs.readFileSync(filePath, { encoding: "utf-8" }); const result = compiler.compile(content, { filePath }); - fs.writeFileSync(`${filePath}.c`, result, { encoding: "utf-8" }); + fs.writeFileSync(`${filePath}.h`, result, { encoding: "utf-8" }); } export function compile(file, options) { diff --git a/lib/compiler/json.js b/lib/compiler/json.js index 10d1fbb..f8ee5e4 100644 --- a/lib/compiler/json.js +++ b/lib/compiler/json.js @@ -7,15 +7,15 @@ function toIdent(str) { return str.replace(/[^a-zA-Z0-9]/g, "_"); } -function compile(jsonData, { filePath }) { +function compile(jsonData, { filePath, indent = 8 }) { let count = 0; const { name: fileName, base: fileBase } = path.parse(filePath); const identPrefix = toIdent(fileName); const globalLines = []; - const initLines = []; + const resourceLines = []; const refs = []; - const uiLines = []; - const indentStr = " "; + const templateLines = []; + const indentStr = " ".repeat(indent); function translateNode(name, data) { let ident; @@ -52,33 +52,30 @@ function compile(jsonData, { filePath }) { break; case "resource": if (attrs.type.startsWith("application/font")) { - initLines.push( + resourceLines.push( `pd_font_library_load_file(${JSON.stringify(attrs.src)});` ); return; } if (["text/css", "text/scss", "text/sass"].includes(attrs.type)) { - let cssFilePath; - let cssText; + const options = { filePath }; + let cssText = text; if (attrs.src) { - cssFilePath = path.resolve(filePath, "..", attrs.src); - cssText = fs.readFileSync(cssFilePath, { + options.filePath = path.resolve(filePath, "..", attrs.src); + cssText = fs.readFileSync(options.filePath, { encoding: "utf-8", }); - } else { - cssFilePath = filePath; - cssText = text; } const cssCode = attrs.type === "text/css" - ? css.compile(cssText) - : sass.compile(cssText); - ident = cssCode.substring("const char *".length).split(" ")[0]; + ? css.compile(cssText, options) + : sass.compile(cssText, options); + ident = cssCode.substring("static const char *".length).split(" ")[0]; globalLines.push(cssCode); - initLines.push( + resourceLines.push( `ui_load_css_string(${ident}, ${JSON.stringify( - path.parse(cssFilePath).base + path.parse(options.filePath).base )});` ); } @@ -96,12 +93,12 @@ function compile(jsonData, { filePath }) { } else { ident = `w[${count++}]`; } - uiLines.push( + templateLines.push( `${ident} = ui_create_widget(${type ? `"${type}"` : "NULL"});` ); Object.keys(attrs).forEach((attrName) => { if (attrName === "class") { - uiLines.push( + templateLines.push( `ui_widget_add_class(${ident}, ${JSON.stringify( attrs[attrName] )});` @@ -111,19 +108,24 @@ function compile(jsonData, { filePath }) { if (attrName === "ref") { return; } - uiLines.push( + templateLines.push( `ui_widget_set_attr(${ident}, "${attrName}", ${JSON.stringify( attrs[attrName] )});` ); }); + if (text) { + templateLines.push( + `ui_widget_set_text(${ident}, ${JSON.stringify(text)});` + ); + } break; } children .map(([childName, childData]) => translateNode(childName, childData)) .forEach((childIdent) => { if (ident && childIdent) { - uiLines.push(`ui_widget_append(${ident}, ${childIdent});`); + templateLines.push(`ui_widget_append(${ident}, ${childIdent});`); } }); return ident; @@ -144,21 +146,24 @@ function compile(jsonData, { filePath }) { : []), ...globalLines, "", - `static void ${identPrefix}_create(ui_widget_t *${identPrefix}_parent, ${identPrefix}_refs_t *refs)`, - "{", - ...[ - `ui_widget_t *w[${count}];`, - "", - ...uiLines, - `return ${identPrefix}_parent;`, - ].map((line) => (line ? `${indentStr}${line}` : line)), - "}", - "", - `static void ${identPrefix}_install(void)`, + `static void ${identPrefix}_load_template(ui_widget_t *${identPrefix}_parent${ + refs.length > 0 ? `, ${identPrefix}_refs_t *refs` : "" + })`, "{", - ...initLines.map((line) => (line ? `${indentStr}${line}` : line)), + ...[`ui_widget_t *w[${count}];`, "", ...templateLines].map((line) => + line ? `${indentStr}${line}` : line + ), "}", "", + ...(resourceLines.length > 0 + ? [ + `static void ${identPrefix}_load_resources(void)`, + "{", + ...resourceLines.map((line) => (line ? `${indentStr}${line}` : line)), + "}", + "", + ] + : []), ].join("\n"); } diff --git a/lib/compiler/sass.js b/lib/compiler/sass.js index 3eab138..4ec2071 100644 --- a/lib/compiler/sass.js +++ b/lib/compiler/sass.js @@ -1,9 +1,35 @@ -import sass from "sass"; +import fs from "fs-extra"; +import path from "path"; +import * as sass from "sass"; import css from "./css.js"; +export function compileSass(input, filePath) { + const { dir, ext } = path.parse(filePath); + return sass.compileString(input, { + importer: { + findFileUrl(url) { + const resolvedUrl = path.resolve(dir, url); + const parsedUrl = path.parse(resolvedUrl); + const result = [ + resolvedUrl, + `${resolvedUrl}${ext}`, + path.join(parsedUrl.dir, `_${parsedUrl.base}`), + path.join(parsedUrl.dir, `_${parsedUrl.base}${ext}`), + path.join(resolvedUrl, `index${ext}`), + ].find((item) => fs.existsSync(item) && fs.statSync(item).isFile()); + return result ? new URL(`file://${result}`) : null; + }, + }, + }); +} + export default { - test: /\.s[ac]ss$/, - compile(file) { - return css.compile(sass.compile(file)); + test(filePath) { + const { ext, name } = path.parse(filePath); + return (ext === ".sass" || ext === ".scss") && !name.startsWith("_"); + }, + compile(input, options) { + const result = compileSass(input, options.filePath); + return css.compile(result.css); }, };