@weave-framework/cli 0.2.53 → 0.2.162
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -0
- package/bin/weave.mjs +3 -0
- package/dist/cli.js +244 -30
- package/dist/styles.d.ts +1 -1
- package/package.json +3 -2
package/README.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# @weave-framework/cli
|
|
2
|
+
|
|
3
|
+
The Weave CLI — `weave build`, `weave dev` (watch + live-reload), `weave check`, `weave routes`.
|
|
4
|
+
|
|
5
|
+
Part of **[Weave](https://weaveframework.dev/)** — a fine-grained reactive, signal-native UI framework: no Virtual DOM, zero third-party runtime dependencies.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -D @weave-framework/cli
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Scaffolded apps already include it (with scripts wired up):
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm create weave@latest my-app
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
📚 **Guides + full API reference:** [weaveframework.dev](https://weaveframework.dev/)
|
|
18
|
+
|
|
19
|
+
## License
|
|
20
|
+
|
|
21
|
+
MIT
|
package/bin/weave.mjs
CHANGED
|
@@ -23,6 +23,9 @@ await esbuild({
|
|
|
23
23
|
bundle: true,
|
|
24
24
|
format: 'esm',
|
|
25
25
|
platform: 'node',
|
|
26
|
+
// NB: @weave-framework/mcp stays INLINED in the dev bin (unlike the prod build, which
|
|
27
|
+
// externalizes it) — the dev bundle runs from node_modules/.weave/, whose module
|
|
28
|
+
// resolution can't reach the workspace-linked package, so we bundle it in.
|
|
26
29
|
external: ['esbuild', 'typescript', 'sass'],
|
|
27
30
|
outfile: out,
|
|
28
31
|
});
|
package/dist/cli.js
CHANGED
|
@@ -507,6 +507,9 @@ var Parser = class {
|
|
|
507
507
|
if (rawName.startsWith("class:")) {
|
|
508
508
|
return { type: "class", name: rawName.slice(6), expr: exprOf(), offset };
|
|
509
509
|
}
|
|
510
|
+
if (rawName.startsWith("style:")) {
|
|
511
|
+
return { type: "style", name: rawName.slice(6), expr: exprOf(), offset };
|
|
512
|
+
}
|
|
510
513
|
if (rawName.startsWith("bind:")) {
|
|
511
514
|
return { type: "bind", name: rawName.slice(5), expr: exprOf(), offset };
|
|
512
515
|
}
|
|
@@ -741,10 +744,11 @@ function rewrite(expr, scope, ctxRef = "ctx") {
|
|
|
741
744
|
const name = expr.slice(i, j);
|
|
742
745
|
const isProperty = lastNonSpace(out) === ".";
|
|
743
746
|
const binding = scope.get(name);
|
|
744
|
-
|
|
747
|
+
const prev = lastNonSpace(out);
|
|
748
|
+
const next = firstNonSpaceFrom(expr, j);
|
|
749
|
+
const isObjectKey = (prev === "{" || prev === ",") && next === ":";
|
|
750
|
+
if (binding && !isProperty && !isObjectKey) {
|
|
745
751
|
if (binding.kind !== "local") {
|
|
746
|
-
const prev = lastNonSpace(out);
|
|
747
|
-
const next = firstNonSpaceFrom(expr, j);
|
|
748
752
|
if ((prev === "{" || prev === ",") && (next === "," || next === "}")) insert(`${name}: `);
|
|
749
753
|
}
|
|
750
754
|
if (binding.kind === "ctx") {
|
|
@@ -943,8 +947,11 @@ function freeIdentifiers(expr) {
|
|
|
943
947
|
let j = i + 1;
|
|
944
948
|
while (j < n && ID_CHAR.test(expr[j])) j++;
|
|
945
949
|
const name = expr.slice(i, j);
|
|
946
|
-
const
|
|
947
|
-
|
|
950
|
+
const prev = lastNonSpace(expr.slice(0, i));
|
|
951
|
+
const next = firstNonSpaceFrom(expr, j);
|
|
952
|
+
const isProperty = prev === ".";
|
|
953
|
+
const isObjectKey = (prev === "{" || prev === ",") && next === ":";
|
|
954
|
+
if (!isProperty && !isObjectKey && !NON_CTX.has(name) && !params.has(name)) out.add(name);
|
|
948
955
|
i = j;
|
|
949
956
|
continue;
|
|
950
957
|
}
|
|
@@ -978,6 +985,8 @@ var Gen = class {
|
|
|
978
985
|
// @weave-framework/runtime/dom helpers
|
|
979
986
|
usedCore = /* @__PURE__ */ new Set();
|
|
980
987
|
// @weave-framework/runtime primitives (computed, …)
|
|
988
|
+
usedComponents = /* @__PURE__ */ new Set();
|
|
989
|
+
// PascalCase child tags referenced in module mode
|
|
981
990
|
templates = [];
|
|
982
991
|
tplN = 0;
|
|
983
992
|
fnN = 0;
|
|
@@ -989,13 +998,19 @@ var Gen = class {
|
|
|
989
998
|
this.usedCore.add(name);
|
|
990
999
|
return this.mode === "function" ? `rt.${name}` : name;
|
|
991
1000
|
}
|
|
992
|
-
/**
|
|
1001
|
+
/**
|
|
1002
|
+
* Reference a child component: from the `_c` map in function mode, bare (imported)
|
|
1003
|
+
* in module mode. In module mode the bare identifier must be in the emitted module's
|
|
1004
|
+
* scope — the loader resolves each recorded tag to a real `import` (see the plugin's
|
|
1005
|
+
* child-import injection), or the component's own `<script>` imports it explicitly.
|
|
1006
|
+
*/
|
|
993
1007
|
Comp(name) {
|
|
1008
|
+
this.usedComponents.add(name);
|
|
994
1009
|
return this.mode === "function" ? `_c.${name}` : name;
|
|
995
1010
|
}
|
|
996
|
-
tpl(html) {
|
|
1011
|
+
tpl(html, svg = false) {
|
|
997
1012
|
const v = `_t${this.tplN++}`;
|
|
998
|
-
this.templates.push(`const ${v} = ${this.H("template")}(${JSON.stringify(html)});`);
|
|
1013
|
+
this.templates.push(`const ${v} = ${this.H(svg ? "templateSvg" : "template")}(${JSON.stringify(html)});`);
|
|
999
1014
|
return v;
|
|
1000
1015
|
}
|
|
1001
1016
|
fn(prefix = "_b") {
|
|
@@ -1008,15 +1023,79 @@ function compileTemplate(input, options = {}) {
|
|
|
1008
1023
|
const gen = new Gen(mode, options.scopeAttr, options.hostAttr);
|
|
1009
1024
|
const ast = parseTemplate(input);
|
|
1010
1025
|
const render = compileFragment(gen, ast, ctxScope(options.scope ?? []), "render", "ctx, slots", true);
|
|
1026
|
+
const components = [...gen.usedComponents];
|
|
1011
1027
|
if (mode === "function") {
|
|
1012
1028
|
const body = [...gen.templates, render, "return render(ctx, {});"].join("\n");
|
|
1013
|
-
return { code: body };
|
|
1029
|
+
return { code: body, components };
|
|
1014
1030
|
}
|
|
1015
1031
|
const domImport = `import { ${[...gen.used].sort().join(", ")} } from ${JSON.stringify(runtimeImport)};`;
|
|
1016
1032
|
const coreImport = gen.usedCore.size ? `import { ${[...gen.usedCore].sort().join(", ")} } from "@weave-framework/runtime";
|
|
1017
1033
|
` : "";
|
|
1018
1034
|
const code = [domImport + "\n" + coreImport, ...gen.templates, `export default ${render}`].join("\n");
|
|
1019
|
-
return { code };
|
|
1035
|
+
return { code, components };
|
|
1036
|
+
}
|
|
1037
|
+
var SVG_TAGS = /* @__PURE__ */ new Set([
|
|
1038
|
+
"path",
|
|
1039
|
+
"rect",
|
|
1040
|
+
"circle",
|
|
1041
|
+
"ellipse",
|
|
1042
|
+
"line",
|
|
1043
|
+
"polyline",
|
|
1044
|
+
"polygon",
|
|
1045
|
+
"g",
|
|
1046
|
+
"defs",
|
|
1047
|
+
"use",
|
|
1048
|
+
"symbol",
|
|
1049
|
+
"marker",
|
|
1050
|
+
"mask",
|
|
1051
|
+
"pattern",
|
|
1052
|
+
"clipPath",
|
|
1053
|
+
"linearGradient",
|
|
1054
|
+
"radialGradient",
|
|
1055
|
+
"stop",
|
|
1056
|
+
"image",
|
|
1057
|
+
"foreignObject",
|
|
1058
|
+
"text",
|
|
1059
|
+
"tspan",
|
|
1060
|
+
"textPath",
|
|
1061
|
+
"desc",
|
|
1062
|
+
"view",
|
|
1063
|
+
"filter",
|
|
1064
|
+
"feBlend",
|
|
1065
|
+
"feColorMatrix",
|
|
1066
|
+
"feComponentTransfer",
|
|
1067
|
+
"feComposite",
|
|
1068
|
+
"feConvolveMatrix",
|
|
1069
|
+
"feDiffuseLighting",
|
|
1070
|
+
"feDisplacementMap",
|
|
1071
|
+
"feDropShadow",
|
|
1072
|
+
"feFlood",
|
|
1073
|
+
"feFuncA",
|
|
1074
|
+
"feFuncB",
|
|
1075
|
+
"feFuncG",
|
|
1076
|
+
"feFuncR",
|
|
1077
|
+
"feGaussianBlur",
|
|
1078
|
+
"feImage",
|
|
1079
|
+
"feMerge",
|
|
1080
|
+
"feMergeNode",
|
|
1081
|
+
"feMorphology",
|
|
1082
|
+
"feOffset",
|
|
1083
|
+
"feSpecularLighting",
|
|
1084
|
+
"feTile",
|
|
1085
|
+
"feTurbulence",
|
|
1086
|
+
"animate",
|
|
1087
|
+
"animateMotion",
|
|
1088
|
+
"animateTransform",
|
|
1089
|
+
"mpath",
|
|
1090
|
+
"set"
|
|
1091
|
+
]);
|
|
1092
|
+
var TRANSITION_PHASES = /* @__PURE__ */ new Set(["enterstart", "enterend", "leavestart", "leaveend"]);
|
|
1093
|
+
function pascalToKebab(tag) {
|
|
1094
|
+
return tag.replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1-$2").toLowerCase();
|
|
1095
|
+
}
|
|
1096
|
+
function childImportCandidates(tag) {
|
|
1097
|
+
const k = pascalToKebab(tag);
|
|
1098
|
+
return [`../${k}/${k}`, `./${k}`, `./${k}/${k}`];
|
|
1020
1099
|
}
|
|
1021
1100
|
function compileFragment(gen, nodes, scope, name, param = "", isHost = false) {
|
|
1022
1101
|
const top = trimTop(nodes);
|
|
@@ -1180,6 +1259,9 @@ function compileFragment(gen, nodes, scope, name, param = "", isHost = false) {
|
|
|
1180
1259
|
case "class":
|
|
1181
1260
|
sink.push(`${gen.H("bindClass")}(${n}, ${q(attr.name)}, () => ${rewrite(attr.expr, sc).code});`);
|
|
1182
1261
|
break;
|
|
1262
|
+
case "style":
|
|
1263
|
+
sink.push(`${gen.H("bindStyleProp")}(${n}, ${q(attr.name)}, () => ${rewrite(attr.expr, sc).code});`);
|
|
1264
|
+
break;
|
|
1183
1265
|
case "show":
|
|
1184
1266
|
sink.push(`${gen.H("bindShow")}(${n}, () => ${rewrite(attr.expr, sc).code});`);
|
|
1185
1267
|
break;
|
|
@@ -1190,6 +1272,10 @@ function compileFragment(gen, nodes, scope, name, param = "", isHost = false) {
|
|
|
1190
1272
|
break;
|
|
1191
1273
|
}
|
|
1192
1274
|
case "event": {
|
|
1275
|
+
if (TRANSITION_PHASES.has(attr.name)) {
|
|
1276
|
+
sink.push(`${gen.H("transitionEvent")}(${n}, ${q(attr.name)}, ${rewrite(attr.expr, sc).code});`);
|
|
1277
|
+
break;
|
|
1278
|
+
}
|
|
1193
1279
|
const handler = wrapHandler(attr, sc);
|
|
1194
1280
|
const opts = eventOpts(attr.modifiers);
|
|
1195
1281
|
sink.push(`${gen.H("listen")}(${n}, ${q(attr.name)}, ${handler}${opts ? `, ${opts}` : ""});`);
|
|
@@ -1201,7 +1287,7 @@ function compileFragment(gen, nodes, scope, name, param = "", isHost = false) {
|
|
|
1201
1287
|
case "use": {
|
|
1202
1288
|
const action = rewrite(attr.name, sc).code;
|
|
1203
1289
|
sink.push(
|
|
1204
|
-
attr.expr !== void 0 ? `${gen.H("applyAction")}(${n}, ${action}, ${rewrite(attr.expr, sc).code});` : `${gen.H("applyAction")}(${n}, ${action});`
|
|
1290
|
+
attr.expr !== void 0 ? `${gen.H("applyAction")}(${n}, ${action}, () => ${rewrite(attr.expr, sc).code});` : `${gen.H("applyAction")}(${n}, ${action});`
|
|
1205
1291
|
);
|
|
1206
1292
|
break;
|
|
1207
1293
|
}
|
|
@@ -1384,8 +1470,10 @@ function compileFragment(gen, nodes, scope, name, param = "", isHost = false) {
|
|
|
1384
1470
|
}
|
|
1385
1471
|
if (singleRoot) emitElement(sole, [], scope, isHost);
|
|
1386
1472
|
else emitChildren(top, [], scope, isHost);
|
|
1473
|
+
const topEls = top.filter((n) => n.type === "element");
|
|
1474
|
+
const svgRoot = topEls.length > 0 && SVG_TAGS.has(topEls[0].tag);
|
|
1387
1475
|
const ctor = singleRoot ? gen.H("clone") : gen.H("cloneFragment");
|
|
1388
|
-
const tplVar = gen.tpl(html);
|
|
1476
|
+
const tplVar = gen.tpl(html, svgRoot);
|
|
1389
1477
|
const body = [
|
|
1390
1478
|
`const _r = ${ctor}(${tplVar});`,
|
|
1391
1479
|
...nodeDecls,
|
|
@@ -1852,7 +1940,7 @@ function compileComponent(src, opts = {}) {
|
|
|
1852
1940
|
renderBody,
|
|
1853
1941
|
`export default defineComponent(${setupArg});`
|
|
1854
1942
|
].filter(Boolean).join("\n\n");
|
|
1855
|
-
return { code, css, hash };
|
|
1943
|
+
return { code, css, hash, components: compiled.components };
|
|
1856
1944
|
}
|
|
1857
1945
|
function parseSfcLoc(source) {
|
|
1858
1946
|
const script = locateBlock(source, "script");
|
|
@@ -1916,7 +2004,7 @@ function extractBlock(source, tag) {
|
|
|
1916
2004
|
}
|
|
1917
2005
|
|
|
1918
2006
|
// packages/compiler/src/sources.ts
|
|
1919
|
-
var DECL = /export\s+const\s+(template|styles)\s*(?::[
|
|
2007
|
+
var DECL = /export\s+const\s+(template|styles)\s*(?::[^=\n]+)?=\s*/g;
|
|
1920
2008
|
function extractSources(script) {
|
|
1921
2009
|
let template;
|
|
1922
2010
|
let templateRange;
|
|
@@ -1948,10 +2036,30 @@ function extractSources(script) {
|
|
|
1948
2036
|
function parseLiteral(src, i, kind) {
|
|
1949
2037
|
i = skipWs(src, i);
|
|
1950
2038
|
const c = src[i];
|
|
1951
|
-
if (c === '"' || c === "'" || c === "`") return
|
|
2039
|
+
if (c === '"' || c === "'" || c === "`") return parseConcat(src, i);
|
|
1952
2040
|
if (c === "[") return parseArray(src, i);
|
|
1953
2041
|
throw new Error(`weave: \`${kind}\` must be a static string${kind === "styles" ? " or array of strings" : ""}`);
|
|
1954
2042
|
}
|
|
2043
|
+
function parseConcat(src, i) {
|
|
2044
|
+
const first = parseString(src, i);
|
|
2045
|
+
let value = first.value;
|
|
2046
|
+
let end = first.end;
|
|
2047
|
+
let single = true;
|
|
2048
|
+
for (; ; ) {
|
|
2049
|
+
const plus = skipWs(src, end);
|
|
2050
|
+
if (src[plus] !== "+") break;
|
|
2051
|
+
const nextStart = skipWs(src, plus + 1);
|
|
2052
|
+
const c = src[nextStart];
|
|
2053
|
+
if (c !== '"' && c !== "'" && c !== "`") {
|
|
2054
|
+
throw new Error("weave: `template`/`styles` must be a static string \u2014 `+` may only join string literals");
|
|
2055
|
+
}
|
|
2056
|
+
const next = parseString(src, nextStart);
|
|
2057
|
+
value += next.value;
|
|
2058
|
+
end = next.end;
|
|
2059
|
+
single = false;
|
|
2060
|
+
}
|
|
2061
|
+
return single ? { value, end, innerStart: first.innerStart, innerEnd: first.innerEnd } : { value, end };
|
|
2062
|
+
}
|
|
1955
2063
|
function parseString(src, i) {
|
|
1956
2064
|
const quote = src[i];
|
|
1957
2065
|
const innerStart = i + 1;
|
|
@@ -1983,7 +2091,7 @@ function parseArray(src, i) {
|
|
|
1983
2091
|
j++;
|
|
1984
2092
|
continue;
|
|
1985
2093
|
}
|
|
1986
|
-
const str =
|
|
2094
|
+
const str = parseConcat(src, j);
|
|
1987
2095
|
items.push(str.value);
|
|
1988
2096
|
j = str.end;
|
|
1989
2097
|
}
|
|
@@ -2028,15 +2136,18 @@ function langFromExt(file) {
|
|
|
2028
2136
|
if (file.endsWith(".sass")) return "sass";
|
|
2029
2137
|
return "css";
|
|
2030
2138
|
}
|
|
2139
|
+
function pkgImporters(sass) {
|
|
2140
|
+
return [new sass.NodePackageImporter()];
|
|
2141
|
+
}
|
|
2031
2142
|
async function compileStyleFile(path) {
|
|
2032
2143
|
if (langFromExt(path) === "css") return readFile(path, "utf8");
|
|
2033
2144
|
const sass = await import("sass");
|
|
2034
|
-
return sass.compile(path).css;
|
|
2145
|
+
return sass.compile(path, { importers: pkgImporters(sass) }).css;
|
|
2035
2146
|
}
|
|
2036
2147
|
async function compileStyleFileTracked(path) {
|
|
2037
2148
|
if (langFromExt(path) === "css") return { css: await readFile(path, "utf8"), files: [path] };
|
|
2038
2149
|
const sass = await import("sass");
|
|
2039
|
-
const result = sass.compile(path);
|
|
2150
|
+
const result = sass.compile(path, { importers: pkgImporters(sass) });
|
|
2040
2151
|
const files = result.loadedUrls.filter((u) => u.protocol === "file:").map((u) => fileURLToPath(u));
|
|
2041
2152
|
return { css: result.css, files };
|
|
2042
2153
|
}
|
|
@@ -2045,15 +2156,24 @@ async function compileStyleSource(source, lang, fromDir) {
|
|
|
2045
2156
|
const sass = await import("sass");
|
|
2046
2157
|
return sass.compileString(source, {
|
|
2047
2158
|
syntax: lang === "sass" ? "indented" : "scss",
|
|
2048
|
-
loadPaths: fromDir ? [fromDir] : []
|
|
2159
|
+
loadPaths: fromDir ? [fromDir] : [],
|
|
2160
|
+
importers: pkgImporters(sass)
|
|
2049
2161
|
}).css;
|
|
2050
2162
|
}
|
|
2051
2163
|
|
|
2052
2164
|
// packages/cli/src/plugin.ts
|
|
2165
|
+
function styleId(css) {
|
|
2166
|
+
let h = 5381;
|
|
2167
|
+
for (let i = 0; i < css.length; i++) h = Math.imul(h, 33) ^ css.charCodeAt(i) | 0;
|
|
2168
|
+
return "w-css-" + (h >>> 0).toString(36);
|
|
2169
|
+
}
|
|
2053
2170
|
function cssInjector(css) {
|
|
2054
2171
|
if (!css) return "";
|
|
2172
|
+
const id = styleId(css);
|
|
2055
2173
|
return `
|
|
2056
|
-
;(()=>{const
|
|
2174
|
+
;(()=>{const id=${JSON.stringify(
|
|
2175
|
+
id
|
|
2176
|
+
)};if(document.getElementById(id))return;const s=document.createElement("style");s.id=id;s.textContent=${JSON.stringify(
|
|
2057
2177
|
css
|
|
2058
2178
|
)};document.head.appendChild(s);})();
|
|
2059
2179
|
`;
|
|
@@ -2100,6 +2220,78 @@ async function resolveStyles(decl, tsPath, dir, styleLang) {
|
|
|
2100
2220
|
const compiled = await compileStyleFileTracked(siblingStyle);
|
|
2101
2221
|
return { css: compiled.css, files: compiled.files };
|
|
2102
2222
|
}
|
|
2223
|
+
function stripComments(code) {
|
|
2224
|
+
let out = "";
|
|
2225
|
+
let i = 0;
|
|
2226
|
+
const n = code.length;
|
|
2227
|
+
while (i < n) {
|
|
2228
|
+
const c = code[i];
|
|
2229
|
+
const d = code[i + 1];
|
|
2230
|
+
if (c === '"' || c === "'" || c === "`") {
|
|
2231
|
+
const quote = c;
|
|
2232
|
+
out += c;
|
|
2233
|
+
i++;
|
|
2234
|
+
while (i < n) {
|
|
2235
|
+
const ch = code[i];
|
|
2236
|
+
if (ch === "\\") {
|
|
2237
|
+
out += ch + (code[i + 1] ?? "");
|
|
2238
|
+
i += 2;
|
|
2239
|
+
continue;
|
|
2240
|
+
}
|
|
2241
|
+
out += ch;
|
|
2242
|
+
i++;
|
|
2243
|
+
if (ch === quote) break;
|
|
2244
|
+
}
|
|
2245
|
+
continue;
|
|
2246
|
+
}
|
|
2247
|
+
if (c === "/" && d === "/") {
|
|
2248
|
+
while (i < n && code[i] !== "\n") i++;
|
|
2249
|
+
continue;
|
|
2250
|
+
}
|
|
2251
|
+
if (c === "/" && d === "*") {
|
|
2252
|
+
i += 2;
|
|
2253
|
+
while (i < n && !(code[i] === "*" && code[i + 1] === "/")) i++;
|
|
2254
|
+
i += 2;
|
|
2255
|
+
continue;
|
|
2256
|
+
}
|
|
2257
|
+
out += c;
|
|
2258
|
+
i++;
|
|
2259
|
+
}
|
|
2260
|
+
return out;
|
|
2261
|
+
}
|
|
2262
|
+
function importsBinding(script, name) {
|
|
2263
|
+
if (!script) return false;
|
|
2264
|
+
const code = stripComments(script);
|
|
2265
|
+
const word = new RegExp(`\\b${name}\\b`);
|
|
2266
|
+
const IMPORT = /import\s+([^;]*?)\s+from\s+['"][^'"]+['"]/g;
|
|
2267
|
+
let m;
|
|
2268
|
+
while ((m = IMPORT.exec(code)) !== null) {
|
|
2269
|
+
if (word.test(m[1])) return true;
|
|
2270
|
+
}
|
|
2271
|
+
return false;
|
|
2272
|
+
}
|
|
2273
|
+
function resolveChildModule(tag, dir) {
|
|
2274
|
+
for (const cand of childImportCandidates(tag)) {
|
|
2275
|
+
for (const ext of [".ts", ".weave"]) {
|
|
2276
|
+
if (existsSync(resolve(dir, cand + ext))) return cand;
|
|
2277
|
+
}
|
|
2278
|
+
}
|
|
2279
|
+
return null;
|
|
2280
|
+
}
|
|
2281
|
+
function injectChildImports(code, components, dir, script, filename) {
|
|
2282
|
+
const imports = [];
|
|
2283
|
+
for (const tag of components) {
|
|
2284
|
+
if (importsBinding(script, tag)) continue;
|
|
2285
|
+
const cand = resolveChildModule(tag, dir);
|
|
2286
|
+
if (cand === null) {
|
|
2287
|
+
throw new Error(
|
|
2288
|
+
`weave: ${filename} composes <${tag}> but no import for it was found. Import it in the component's script, or place its module at ${childImportCandidates(tag).map((c) => `${c}.ts`).join(" / ")} (relative to the component).`
|
|
2289
|
+
);
|
|
2290
|
+
}
|
|
2291
|
+
imports.push(`import ${tag} from ${JSON.stringify(cand + ".js")};`);
|
|
2292
|
+
}
|
|
2293
|
+
return imports.length ? imports.join("\n") + "\n" + code : code;
|
|
2294
|
+
}
|
|
2103
2295
|
function weave(state, options = {}) {
|
|
2104
2296
|
const styleLang = options.styleLang ?? "css";
|
|
2105
2297
|
const dev2 = options.dev ?? false;
|
|
@@ -2118,8 +2310,9 @@ function weave(state, options = {}) {
|
|
|
2118
2310
|
const source = await readFile2(args.path, "utf8");
|
|
2119
2311
|
const src = parseSfc(source);
|
|
2120
2312
|
const styles = src.styles ? await compileStyleSource(src.styles, styleLang, dirname(args.path)) : void 0;
|
|
2121
|
-
const { code, css } = compileComponent({ ...src, styles }, { filename: args.path });
|
|
2122
|
-
|
|
2313
|
+
const { code, css, components } = compileComponent({ ...src, styles }, { filename: args.path });
|
|
2314
|
+
const wired = injectChildImports(code, components, dirname(args.path), src.script, args.path);
|
|
2315
|
+
return emit2(wired, css, dirname(args.path));
|
|
2123
2316
|
});
|
|
2124
2317
|
build2.onLoad({ filter: /\.ts$/ }, async (args) => {
|
|
2125
2318
|
if (args.path.includes("node_modules")) return void 0;
|
|
@@ -2142,11 +2335,12 @@ function weave(state, options = {}) {
|
|
|
2142
2335
|
dir,
|
|
2143
2336
|
styleLang
|
|
2144
2337
|
);
|
|
2145
|
-
const { code, css } = compileComponent(
|
|
2338
|
+
const { code, css, components } = compileComponent(
|
|
2146
2339
|
{ script: decl.script, template: template.text, styles: styles.css },
|
|
2147
2340
|
{ filename: args.path }
|
|
2148
2341
|
);
|
|
2149
|
-
|
|
2342
|
+
const wired = injectChildImports(code, components, dir, decl.script, args.path);
|
|
2343
|
+
return { ...emit2(wired, css, dir), watchFiles: [...template.files, ...styles.files] };
|
|
2150
2344
|
});
|
|
2151
2345
|
}
|
|
2152
2346
|
};
|
|
@@ -2309,7 +2503,7 @@ async function build(config) {
|
|
|
2309
2503
|
import { context } from "esbuild";
|
|
2310
2504
|
import { createServer } from "node:http";
|
|
2311
2505
|
import { mkdir as mkdir2, writeFile as writeFile2, readFile as readFile4 } from "node:fs/promises";
|
|
2312
|
-
import { join as join3, extname, relative as relative2, sep as sep2 } from "node:path";
|
|
2506
|
+
import { join as join3, extname, relative as relative2, sep as sep2, isAbsolute } from "node:path";
|
|
2313
2507
|
var RELOAD_PATH = "/__weave_reload";
|
|
2314
2508
|
var MIME = {
|
|
2315
2509
|
".html": "text/html; charset=utf-8",
|
|
@@ -2336,7 +2530,7 @@ async function devInMemory(config) {
|
|
|
2336
2530
|
const css = (await Promise.all(config.styles.map(compileStyleFile))).join("\n");
|
|
2337
2531
|
if (css)
|
|
2338
2532
|
banner = {
|
|
2339
|
-
js: `(()=>{const s=document.createElement("style");s.textContent=${JSON.stringify(
|
|
2533
|
+
js: `(()=>{const id="w-global-styles";if(document.getElementById(id))return;const s=document.createElement("style");s.id=id;s.textContent=${JSON.stringify(
|
|
2340
2534
|
css
|
|
2341
2535
|
)};document.head.appendChild(s);})();`
|
|
2342
2536
|
};
|
|
@@ -2401,8 +2595,15 @@ async function handleRequest(req, res, config, outputs, clients) {
|
|
|
2401
2595
|
return;
|
|
2402
2596
|
}
|
|
2403
2597
|
if (extname(url)) {
|
|
2598
|
+
const target = join3(config.servedir, url);
|
|
2599
|
+
const rel = relative2(config.servedir, target);
|
|
2600
|
+
if (rel === ".." || rel.startsWith(".." + sep2) || isAbsolute(rel)) {
|
|
2601
|
+
res.writeHead(403);
|
|
2602
|
+
res.end("Forbidden");
|
|
2603
|
+
return;
|
|
2604
|
+
}
|
|
2404
2605
|
try {
|
|
2405
|
-
const buf = await readFile4(
|
|
2606
|
+
const buf = await readFile4(target);
|
|
2406
2607
|
res.writeHead(200, { "content-type": mime(url) });
|
|
2407
2608
|
res.end(buf);
|
|
2408
2609
|
} catch {
|
|
@@ -2604,7 +2805,7 @@ function generateRoutes(dir, opts = {}) {
|
|
|
2604
2805
|
import { build as esbuildBuild } from "esbuild";
|
|
2605
2806
|
import { existsSync as existsSync4 } from "node:fs";
|
|
2606
2807
|
import { readFile as readFile5 } from "node:fs/promises";
|
|
2607
|
-
import { resolve as resolve2, dirname as dirname2, join as join5, isAbsolute } from "node:path";
|
|
2808
|
+
import { resolve as resolve2, dirname as dirname2, join as join5, isAbsolute as isAbsolute2 } from "node:path";
|
|
2608
2809
|
function defineConfig(config) {
|
|
2609
2810
|
return config;
|
|
2610
2811
|
}
|
|
@@ -2648,7 +2849,7 @@ async function importConfigModule(file) {
|
|
|
2648
2849
|
return mod.default ?? mod;
|
|
2649
2850
|
}
|
|
2650
2851
|
function resolveConfig(raw, root) {
|
|
2651
|
-
const abs = (p) =>
|
|
2852
|
+
const abs = (p) => isAbsolute2(p) ? p : resolve2(root, p);
|
|
2652
2853
|
if (!raw.root && !raw.entry) {
|
|
2653
2854
|
throw new Error("weave: config must declare either `root` (generated bootstrap) or `entry` (hand-written)");
|
|
2654
2855
|
}
|
|
@@ -3201,8 +3402,21 @@ weave check: ${errors} error${errors === 1 ? "" : "s"}`);
|
|
|
3201
3402
|
console.log(`weave routes \u2192 ${written}`);
|
|
3202
3403
|
return;
|
|
3203
3404
|
}
|
|
3405
|
+
if (cmd === "mcp") {
|
|
3406
|
+
try {
|
|
3407
|
+
const mcp = await import("@weave-framework/mcp");
|
|
3408
|
+
await mcp.runStdioServer();
|
|
3409
|
+
} catch (e) {
|
|
3410
|
+
console.error(
|
|
3411
|
+
`weave mcp: could not start the MCP server \u2014 is @weave-framework/mcp installed?
|
|
3412
|
+
${e?.message ?? String(e)}`
|
|
3413
|
+
);
|
|
3414
|
+
process.exit(1);
|
|
3415
|
+
}
|
|
3416
|
+
return;
|
|
3417
|
+
}
|
|
3204
3418
|
console.error(
|
|
3205
|
-
"usage: weave <build|dev|check|routes> [entry|paths\u2026] [--config file] [--out dir] [--serve dir] [--port n] [--no-minify] [--eager]"
|
|
3419
|
+
"usage: weave <build|dev|check|routes|mcp> [entry|paths\u2026] [--config file] [--out dir] [--serve dir] [--port n] [--no-minify] [--eager]"
|
|
3206
3420
|
);
|
|
3207
3421
|
process.exit(1);
|
|
3208
3422
|
}
|
package/dist/styles.d.ts
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
export type StyleLang = 'css' | 'scss' | 'sass';
|
|
11
11
|
/** The style language implied by a file extension (defaults to plain CSS). */
|
|
12
12
|
export declare function langFromExt(file: string): StyleLang;
|
|
13
|
-
/** Compile a style FILE to CSS — `@use`/`@import` resolve relative to it. */
|
|
13
|
+
/** Compile a style FILE to CSS — `@use`/`@import` resolve relative to it (+ `pkg:` packages). */
|
|
14
14
|
export declare function compileStyleFile(path: string): Promise<string>;
|
|
15
15
|
/**
|
|
16
16
|
* Like {@link compileStyleFile} but also reports every file the compile pulled in —
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@weave-framework/cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.162",
|
|
4
4
|
"description": "Weave CLI — `weave build`, `weave dev` (watch + live-reload), `weave check`, `weave routes`.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -31,7 +31,8 @@
|
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"esbuild": "^0.25.0",
|
|
34
|
-
"typescript": "^5.7.0"
|
|
34
|
+
"typescript": "^5.7.0",
|
|
35
|
+
"@weave-framework/mcp": "0.2.162"
|
|
35
36
|
},
|
|
36
37
|
"optionalDependencies": {
|
|
37
38
|
"sass": "^1.0.0"
|