@jay-framework/jay-stack-cli 0.23.0 → 0.23.1

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.
@@ -44,10 +44,10 @@ Use `reference` for data sources (contracts, categories). Use `stage-place` for
44
44
  Controls card size in the browse grid:
45
45
 
46
46
  ```yaml
47
- browse:
48
- size: small # 4 per row — color swatches, small tokens
49
- size: medium # 2 per row — default
50
- size: large # 1 per row — full-width previews
47
+ browse:
48
+ size: small # 4 per row — color swatches, small tokens
49
+ size: medium # 2 per row — default
50
+ size: large # 1 per row — full-width previews
51
51
  ```
52
52
 
53
53
  ## Presentation (preview)
@@ -55,19 +55,19 @@ Controls card size in the browse grid:
55
55
  Optional visual preview in the browse grid:
56
56
 
57
57
  ```yaml
58
- # Static image
59
- presentation:
60
- type: image
61
- src: thumbnails/my-plugin/feature.png
62
-
63
- # HTML fragment — must use @scope for CSS isolation
64
- presentation:
65
- type: html-fragment
66
- html: |
67
- <div>
68
- <style>@scope { .demo { color: blue; } }</style>
69
- <div class="demo">Preview content</div>
70
- </div>
58
+ # Static image
59
+ presentation:
60
+ type: image
61
+ src: thumbnails/my-plugin/feature.png
62
+
63
+ # HTML fragment — must use @scope for CSS isolation
64
+ presentation:
65
+ type: html-fragment
66
+ html: |
67
+ <div>
68
+ <style>@scope { .demo { color: blue; } }</style>
69
+ <div class="demo">Preview content</div>
70
+ </div>
71
71
  ```
72
72
 
73
73
  Html-fragment rules:
package/dist/index.js CHANGED
@@ -7,8 +7,8 @@ import path from "path";
7
7
  import fs, { promises } from "fs";
8
8
  import YAML from "yaml";
9
9
  import { getLogger, setDevLogger, createDevLogger } from "@jay-framework/logger";
10
- import { JAY_IMPORT_RESOLVER, parseJayFile, generateElementDefinitionFile, parseContract, generateElementFile, generateServerElementFile, htmlElementTagNameMap, loadLinkedContract, getLinkedContractDir } from "@jay-framework/compiler-jay-html";
11
- import { scanPlugins, listContracts, materializeContracts, SetupNeedsAnswerError, discoverPluginsWithSetup, discoverPluginsWithInit, sortPluginsByDependencies, executePluginSetup, executePluginServerInits, runInitCallbacks } from "@jay-framework/stack-server-runtime";
10
+ import { parseJayFile, JAY_IMPORT_RESOLVER, generateElementDefinitionFile, parseContract, generateElementFile, generateServerElementFile, htmlElementTagNameMap, loadLinkedContract, getLinkedContractDir } from "@jay-framework/compiler-jay-html";
11
+ import { scanPlugins, listContracts, materializeContracts, SetupNeedsAnswerError, discoverPluginsWithSetup, sortPluginsByDependencies, discoverPluginsWithInit, executePluginSetup, executePluginServerInits, runInitCallbacks } from "@jay-framework/stack-server-runtime";
12
12
  import { listContracts as listContracts2, materializeContracts as materializeContracts2 } from "@jay-framework/stack-server-runtime";
13
13
  import { Command } from "commander";
14
14
  import chalk from "chalk";
@@ -19,7 +19,7 @@ import { createRequire } from "module";
19
19
  import { glob } from "glob";
20
20
  import fsSync from "node:fs";
21
21
  import { fileURLToPath } from "node:url";
22
- import { input, confirm, select } from "@inquirer/prompts";
22
+ import { select, confirm, input } from "@inquirer/prompts";
23
23
  const DEFAULT_CONFIG = {
24
24
  devServer: {
25
25
  portRange: [3e3, 3100],
@@ -464,17 +464,13 @@ function collectLocalInterfaces(sourceFile) {
464
464
  function collectContractImportedTypes(sourceFile) {
465
465
  const contractTypes = /* @__PURE__ */ new Set();
466
466
  for (const statement of sourceFile.statements) {
467
- if (!u.isImportDeclaration(statement))
468
- continue;
467
+ if (!u.isImportDeclaration(statement)) continue;
469
468
  const moduleSpecifier = statement.moduleSpecifier;
470
- if (!u.isStringLiteral(moduleSpecifier))
471
- continue;
469
+ if (!u.isStringLiteral(moduleSpecifier)) continue;
472
470
  const modulePath = moduleSpecifier.text;
473
- if (!modulePath.includes(".jay-contract"))
474
- continue;
471
+ if (!modulePath.includes(".jay-contract")) continue;
475
472
  const importClause = statement.importClause;
476
- if (!importClause)
477
- continue;
473
+ if (!importClause) continue;
478
474
  const namedBindings = importClause.namedBindings;
479
475
  if (namedBindings && u.isNamedImports(namedBindings)) {
480
476
  for (const element of namedBindings.elements) {
@@ -510,8 +506,7 @@ function visitNode(node, result) {
510
506
  }
511
507
  if (node.arguments.length > 0) {
512
508
  const arg = node.arguments[0];
513
- if (u.isIdentifier(arg))
514
- ;
509
+ if (u.isIdentifier(arg)) ;
515
510
  }
516
511
  }
517
512
  }
@@ -533,10 +528,8 @@ function extractTypeNames(typeNode) {
533
528
  return [];
534
529
  }
535
530
  function checkPropsConsistency(propsTypeName, localInterfaces, contractImportedTypes, contract, contractName, contractPath, sourcePath, errors, warnings) {
536
- if (FRAMEWORK_PROP_TYPES.has(propsTypeName))
537
- return;
538
- if (contractImportedTypes.has(propsTypeName))
539
- return;
531
+ if (FRAMEWORK_PROP_TYPES.has(propsTypeName)) return;
532
+ if (contractImportedTypes.has(propsTypeName)) return;
540
533
  const prefix = `[${contractName}]`;
541
534
  const iface = localInterfaces.get(propsTypeName);
542
535
  if (!iface) {
@@ -551,8 +544,7 @@ function checkPropsConsistency(propsTypeName, localInterfaces, contractImportedT
551
544
  return;
552
545
  }
553
546
  const ownProperties = iface.properties;
554
- if (ownProperties.length === 0)
555
- return;
547
+ if (ownProperties.length === 0) return;
556
548
  if (!contract.props || contract.props.length === 0) {
557
549
  errors.push({
558
550
  type: "contract-invalid",
@@ -596,10 +588,8 @@ function checkParamsConsistency(paramsTypeNames, localInterfaces, contractImport
596
588
  suggestion: `Add a params section to the contract (e.g., params: { slug: string })`
597
589
  });
598
590
  for (const typeName of paramsTypeNames) {
599
- if (FRAMEWORK_PROP_TYPES.has(typeName))
600
- continue;
601
- if (contractImportedTypes.has(typeName))
602
- continue;
591
+ if (FRAMEWORK_PROP_TYPES.has(typeName)) continue;
592
+ if (contractImportedTypes.has(typeName)) continue;
603
593
  const iface = localInterfaces.get(typeName);
604
594
  if (iface) {
605
595
  const ownProps = iface.properties;
@@ -612,13 +602,10 @@ function checkParamsConsistency(paramsTypeNames, localInterfaces, contractImport
612
602
  return;
613
603
  }
614
604
  for (const typeName of paramsTypeNames) {
615
- if (FRAMEWORK_PROP_TYPES.has(typeName))
616
- continue;
617
- if (contractImportedTypes.has(typeName))
618
- continue;
605
+ if (FRAMEWORK_PROP_TYPES.has(typeName)) continue;
606
+ if (contractImportedTypes.has(typeName)) continue;
619
607
  const iface = localInterfaces.get(typeName);
620
- if (!iface)
621
- continue;
608
+ if (!iface) continue;
622
609
  const ownProperties = iface.properties;
623
610
  const contractParamNames = new Set(contract.params.map((p) => p.name));
624
611
  for (const prop of ownProperties) {
@@ -710,16 +697,13 @@ function requiredString(obj, field, itemPath, errors, code) {
710
697
  }
711
698
  function optionalString(obj, field) {
712
699
  const value = obj[field];
713
- if (value === void 0)
714
- return void 0;
715
- if (typeof value !== "string")
716
- return void 0;
700
+ if (value === void 0) return void 0;
701
+ if (typeof value !== "string") return void 0;
717
702
  const trimmed = value.trim();
718
703
  return trimmed.length > 0 ? trimmed : void 0;
719
704
  }
720
705
  function validateInteraction(raw, itemPath, errors) {
721
- if (raw === void 0)
722
- return void 0;
706
+ if (raw === void 0) return void 0;
723
707
  if (!isRecord$1(raw)) {
724
708
  errors.push({
725
709
  path: itemPath,
@@ -743,8 +727,7 @@ function validateInteraction(raw, itemPath, errors) {
743
727
  };
744
728
  }
745
729
  function validatePresentation(raw, itemPath, errors) {
746
- if (raw === void 0)
747
- return void 0;
730
+ if (raw === void 0) return void 0;
748
731
  if (!isRecord$1(raw)) {
749
732
  errors.push({
750
733
  path: itemPath,
@@ -764,14 +747,12 @@ function validatePresentation(raw, itemPath, errors) {
764
747
  }
765
748
  if (type === "image") {
766
749
  const src = requiredString(raw, "src", itemPath, errors, "presentation-missing-src");
767
- if (!src)
768
- return void 0;
750
+ if (!src) return void 0;
769
751
  return { type: "image", src };
770
752
  }
771
753
  if (type === "gif") {
772
754
  const src = requiredString(raw, "src", itemPath, errors, "presentation-missing-src");
773
- if (!src)
774
- return void 0;
755
+ if (!src) return void 0;
775
756
  return {
776
757
  type: "gif",
777
758
  src,
@@ -816,8 +797,7 @@ function validatePresentation(raw, itemPath, errors) {
816
797
  }
817
798
  const BROWSE_SIZES = /* @__PURE__ */ new Set(["large", "medium", "small"]);
818
799
  function validateBrowse(raw, itemPath, errors) {
819
- if (raw === void 0)
820
- return void 0;
800
+ if (raw === void 0) return void 0;
821
801
  if (!isRecord$1(raw)) {
822
802
  errors.push({
823
803
  path: itemPath,
@@ -841,8 +821,7 @@ function validateBrowse(raw, itemPath, errors) {
841
821
  return { size: sizeRaw };
842
822
  }
843
823
  function validateFolderPath(raw, itemPath, errors) {
844
- if (raw === void 0)
845
- return void 0;
824
+ if (raw === void 0) return void 0;
846
825
  if (!Array.isArray(raw)) {
847
826
  errors.push({
848
827
  path: `${itemPath}.folderPath`,
@@ -980,8 +959,7 @@ function validateAddMenuCatalogFile(raw, sourcePath) {
980
959
  raw.items.forEach((entry, index) => {
981
960
  const result = validateAddMenuItem(entry, `${sourcePath}.items[${index}]`);
982
961
  errors.push(...result.errors);
983
- if (result.item)
984
- items.push(result.item);
962
+ if (result.item) items.push(result.item);
985
963
  });
986
964
  if (items.length === 0 && errors.length > 0) {
987
965
  return { file: null, errors };
@@ -989,11 +967,9 @@ function validateAddMenuCatalogFile(raw, sourcePath) {
989
967
  return { file: { items }, errors };
990
968
  }
991
969
  function normalizeAddMenuPresentation(item) {
992
- if (item.presentation)
993
- return item.presentation;
970
+ if (item.presentation) return item.presentation;
994
971
  const thumbnail = item.thumbnail?.trim();
995
- if (!thumbnail)
996
- return void 0;
972
+ if (!thumbnail) return void 0;
997
973
  if (/\.gif$/i.test(thumbnail)) {
998
974
  return { type: "gif", src: thumbnail };
999
975
  }
@@ -1004,15 +980,12 @@ function normalizeAddMenuBrowseSize(item) {
1004
980
  }
1005
981
  function hasSingleRootDiv(html) {
1006
982
  const trimmed = html.trim();
1007
- if (!trimmed.startsWith("<div"))
1008
- return false;
983
+ if (!trimmed.startsWith("<div")) return false;
1009
984
  const openMatch = trimmed.match(/^<div\b[^>]*>/i);
1010
- if (!openMatch)
1011
- return false;
985
+ if (!openMatch) return false;
1012
986
  const afterOpen = trimmed.slice(openMatch[0].length);
1013
987
  const closeIdx = afterOpen.lastIndexOf("</div>");
1014
- if (closeIdx < 0)
1015
- return false;
988
+ if (closeIdx < 0) return false;
1016
989
  const tail = afterOpen.slice(closeIdx + "</div>".length).trim();
1017
990
  return tail.length === 0;
1018
991
  }
@@ -1088,8 +1061,7 @@ function lintHtmlFragment(item, sourcePath) {
1088
1061
  }
1089
1062
  function lintGifPoster(item, sourcePath) {
1090
1063
  const presentation = normalizeAddMenuPresentation(item);
1091
- if (presentation?.type !== "gif" || presentation.poster?.trim())
1092
- return [];
1064
+ if (presentation?.type !== "gif" || presentation.poster?.trim()) return [];
1093
1065
  return [
1094
1066
  catalogWarning(
1095
1067
  "gif-missing-poster",
@@ -1100,10 +1072,8 @@ function lintGifPoster(item, sourcePath) {
1100
1072
  ];
1101
1073
  }
1102
1074
  function lintBrowseLargeWithoutPresentation(item, sourcePath) {
1103
- if (normalizeAddMenuBrowseSize(item) !== "large")
1104
- return [];
1105
- if (normalizeAddMenuPresentation(item))
1106
- return [];
1075
+ if (normalizeAddMenuBrowseSize(item) !== "large") return [];
1076
+ if (normalizeAddMenuPresentation(item)) return [];
1107
1077
  return [
1108
1078
  catalogWarning(
1109
1079
  "browse-large-without-presentation",
@@ -1176,8 +1146,7 @@ function resolveModulePath$1(basePath) {
1176
1146
  return void 0;
1177
1147
  }
1178
1148
  function collectTypeScriptFiles(dir, depth = 0) {
1179
- if (depth > 4)
1180
- return [];
1149
+ if (depth > 4) return [];
1181
1150
  const entries = fs.readdirSync(dir, { withFileTypes: true });
1182
1151
  const files = [];
1183
1152
  for (const entry of entries) {
@@ -1196,8 +1165,7 @@ function resolveHandlerSourceFile(pluginPath, handlerRef, isNpmPackage) {
1196
1165
  }
1197
1166
  const searchRoots = isNpmPackage ? [path.join(pluginPath, "lib"), path.join(pluginPath, "dist")] : [pluginPath];
1198
1167
  for (const root of searchRoots) {
1199
- if (!fs.existsSync(root))
1200
- continue;
1168
+ if (!fs.existsSync(root)) continue;
1201
1169
  for (const file of collectTypeScriptFiles(root)) {
1202
1170
  const content = fs.readFileSync(file, "utf-8");
1203
1171
  const definesHandler = new RegExp(
@@ -1217,8 +1185,7 @@ function resolveHandlerSourceFile(pluginPath, handlerRef, isNpmPackage) {
1217
1185
  if (reExportMatch) {
1218
1186
  const importSpec = reExportMatch[1].replace(/\.js$/, "");
1219
1187
  const resolved = resolveModulePath$1(path.resolve(path.dirname(file), importSpec));
1220
- if (resolved)
1221
- return resolved;
1188
+ if (resolved) return resolved;
1222
1189
  }
1223
1190
  }
1224
1191
  }
@@ -1228,8 +1195,7 @@ function extractBalancedBlock(source, openBraceIndex) {
1228
1195
  let depth = 0;
1229
1196
  for (let index = openBraceIndex; index < source.length; index++) {
1230
1197
  const char = source[index];
1231
- if (char === "{")
1232
- depth++;
1198
+ if (char === "{") depth++;
1233
1199
  else if (char === "}") {
1234
1200
  depth--;
1235
1201
  if (depth === 0) {
@@ -1249,8 +1215,7 @@ function findFunctionBodyOpenBrace(source, searchFrom) {
1249
1215
  if (parenMatch?.index !== void 0) {
1250
1216
  candidates.push(searchFrom + parenMatch.index + parenMatch[0].length - 1);
1251
1217
  }
1252
- if (candidates.length === 0)
1253
- return -1;
1218
+ if (candidates.length === 0) return -1;
1254
1219
  return Math.min(...candidates);
1255
1220
  }
1256
1221
  function extractFunctionBody(source, functionName) {
@@ -1267,11 +1232,9 @@ function extractFunctionBody(source, functionName) {
1267
1232
  ];
1268
1233
  for (const pattern of patterns) {
1269
1234
  const match = pattern.exec(source);
1270
- if (!match)
1271
- continue;
1235
+ if (!match) continue;
1272
1236
  const braceIndex = findFunctionBodyOpenBrace(source, match.index);
1273
- if (braceIndex === -1)
1274
- continue;
1237
+ if (braceIndex === -1) continue;
1275
1238
  return extractBalancedBlock(source, braceIndex);
1276
1239
  }
1277
1240
  return null;
@@ -1284,11 +1247,9 @@ function extractDefaultExportFunctionBody(source) {
1284
1247
  ];
1285
1248
  for (const pattern of patterns) {
1286
1249
  const match = pattern.exec(source);
1287
- if (!match)
1288
- continue;
1250
+ if (!match) continue;
1289
1251
  const braceIndex = findFunctionBodyOpenBrace(source, match.index);
1290
- if (braceIndex === -1)
1291
- continue;
1252
+ if (braceIndex === -1) continue;
1292
1253
  return extractBalancedBlock(source, braceIndex);
1293
1254
  }
1294
1255
  return null;
@@ -1298,8 +1259,7 @@ function handlerBodyWritesAddMenuCatalog(body) {
1298
1259
  }
1299
1260
  function resolveSetupHandlerFunctionBody(pluginPath, handlerRef, isNpmPackage) {
1300
1261
  const sourceFile = resolveHandlerSourceFile(pluginPath, handlerRef, isNpmPackage);
1301
- if (!sourceFile)
1302
- return null;
1262
+ if (!sourceFile) return null;
1303
1263
  const source = fs.readFileSync(sourceFile, "utf-8");
1304
1264
  if (isRelativeHandlerRef(handlerRef)) {
1305
1265
  return extractDefaultExportFunctionBody(source) ?? extractFunctionBody(source, "setup") ?? extractFunctionBody(source, handlerRef);
@@ -1307,8 +1267,7 @@ function resolveSetupHandlerFunctionBody(pluginPath, handlerRef, isNpmPackage) {
1307
1267
  return extractFunctionBody(source, handlerRef);
1308
1268
  }
1309
1269
  function suggestionForCode(code) {
1310
- if (!code)
1311
- return `See ${CONTRIBUTOR_GUIDE} for schema and validation rules`;
1270
+ if (!code) return `See ${CONTRIBUTOR_GUIDE} for schema and validation rules`;
1312
1271
  return ADD_MENU_VALIDATION_SUGGESTIONS[code] ?? `See ${CONTRIBUTOR_GUIDE} for schema and validation rules`;
1313
1272
  }
1314
1273
  function mapSchemaError$1(error, catalogPath) {
@@ -1338,8 +1297,7 @@ function pluginShipsAddMenuCatalog(context) {
1338
1297
  );
1339
1298
  }
1340
1299
  function validateAddMenuAgentKitHandler(context, result) {
1341
- if (!pluginShipsAddMenuCatalog(context))
1342
- return;
1300
+ if (!pluginShipsAddMenuCatalog(context)) return;
1343
1301
  const agentKitHandler = context.manifest.agentkit;
1344
1302
  if (!agentKitHandler) {
1345
1303
  result.warnings.push({
@@ -1351,15 +1309,13 @@ function validateAddMenuAgentKitHandler(context, result) {
1351
1309
  });
1352
1310
  }
1353
1311
  const setupHandler = typeof context.manifest.setup === "string" ? context.manifest.setup : void 0;
1354
- if (!setupHandler)
1355
- return;
1312
+ if (!setupHandler) return;
1356
1313
  const setupBody = resolveSetupHandlerFunctionBody(
1357
1314
  context.pluginPath,
1358
1315
  setupHandler,
1359
1316
  context.isNpmPackage
1360
1317
  );
1361
- if (!setupBody || !handlerBodyWritesAddMenuCatalog(setupBody))
1362
- return;
1318
+ if (!setupBody || !handlerBodyWritesAddMenuCatalog(setupBody)) return;
1363
1319
  result.warnings.push({
1364
1320
  type: "add-menu-catalog",
1365
1321
  code: "add-menu-legacy-setup-handler",
@@ -1401,8 +1357,7 @@ async function validateAddMenuCatalog(context, result) {
1401
1357
  validateAddMenuAgentKitHandler(context, result);
1402
1358
  for (const relPath of ADD_MENU_CATALOG_REL_PATHS) {
1403
1359
  const catalogPath = path.join(context.pluginPath, relPath);
1404
- if (!fs.existsSync(catalogPath))
1405
- continue;
1360
+ if (!fs.existsSync(catalogPath)) continue;
1406
1361
  await validateAddMenuCatalogFileAtPath(catalogPath, relPath, result);
1407
1362
  }
1408
1363
  }
@@ -2026,16 +1981,14 @@ async function validateSchema(context, result) {
2026
1981
  }
2027
1982
  function checkExportExists(exportName, context) {
2028
1983
  const packageJsonPath = path.join(context.pluginPath, "package.json");
2029
- if (!fs.existsSync(packageJsonPath))
2030
- return true;
1984
+ if (!fs.existsSync(packageJsonPath)) return true;
2031
1985
  let mainPath;
2032
1986
  try {
2033
1987
  const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
2034
1988
  if (packageJson.exports?.["."]) {
2035
1989
  const entry = packageJson.exports["."];
2036
1990
  const entryPath = typeof entry === "string" ? entry : entry.default || entry.import;
2037
- if (entryPath)
2038
- mainPath = path.join(context.pluginPath, entryPath);
1991
+ if (entryPath) mainPath = path.join(context.pluginPath, entryPath);
2039
1992
  }
2040
1993
  if (!mainPath && packageJson.main) {
2041
1994
  mainPath = path.join(context.pluginPath, packageJson.main);
@@ -2043,8 +1996,7 @@ function checkExportExists(exportName, context) {
2043
1996
  } catch {
2044
1997
  return true;
2045
1998
  }
2046
- if (!mainPath || !fs.existsSync(mainPath))
2047
- return true;
1999
+ if (!mainPath || !fs.existsSync(mainPath)) return true;
2048
2000
  try {
2049
2001
  const content = fs.readFileSync(mainPath, "utf-8");
2050
2002
  const patterns = [
@@ -2104,8 +2056,7 @@ function resolveContractFile(contractSpec, context) {
2104
2056
  const resolvedPath = typeof exportValue === "string" ? exportValue : exportValue.default || exportValue.import || exportValue.require;
2105
2057
  if (resolvedPath) {
2106
2058
  const fullPath = path.join(context.pluginPath, resolvedPath);
2107
- if (fs.existsSync(fullPath))
2108
- return fullPath;
2059
+ if (fs.existsSync(fullPath)) return fullPath;
2109
2060
  }
2110
2061
  }
2111
2062
  }
@@ -2114,8 +2065,7 @@ function resolveContractFile(contractSpec, context) {
2114
2065
  }
2115
2066
  for (const dir of ["dist", "lib", ""]) {
2116
2067
  const candidate = path.join(context.pluginPath, dir, contractSpec);
2117
- if (fs.existsSync(candidate))
2118
- return candidate;
2068
+ if (fs.existsSync(candidate)) return candidate;
2119
2069
  }
2120
2070
  return void 0;
2121
2071
  } else {
@@ -2203,8 +2153,7 @@ function hasExportModifier(node) {
2203
2153
  function resolveModulePath(basePath) {
2204
2154
  for (const ext of ["", ".ts", ".js", "/index.ts", "/index.js"]) {
2205
2155
  const candidate = basePath + ext;
2206
- if (fs.existsSync(candidate))
2207
- return candidate;
2156
+ if (fs.existsSync(candidate)) return candidate;
2208
2157
  }
2209
2158
  return void 0;
2210
2159
  }
@@ -2214,10 +2163,8 @@ function resolveComponentSourcePath(componentName, context) {
2214
2163
  const entryFile = resolveModulePath(entryBase);
2215
2164
  const libEntryFile = !entryFile ? resolveModulePath(path.join(context.pluginPath, "lib", modulePath)) : void 0;
2216
2165
  const sourceEntry = entryFile || libEntryFile;
2217
- if (!sourceEntry)
2218
- return void 0;
2219
- if (!sourceEntry.endsWith(".ts"))
2220
- return void 0;
2166
+ if (!sourceEntry) return void 0;
2167
+ if (!sourceEntry.endsWith(".ts")) return void 0;
2221
2168
  let sourceCode;
2222
2169
  try {
2223
2170
  sourceCode = fs.readFileSync(sourceEntry, "utf-8");
@@ -2233,12 +2180,9 @@ function resolveComponentSourcePath(componentName, context) {
2233
2180
  );
2234
2181
  const starReexportModules = [];
2235
2182
  for (const statement of sourceFile.statements) {
2236
- if (!u.isExportDeclaration(statement))
2237
- continue;
2238
- if (!statement.moduleSpecifier)
2239
- continue;
2240
- if (!u.isStringLiteral(statement.moduleSpecifier))
2241
- continue;
2183
+ if (!u.isExportDeclaration(statement)) continue;
2184
+ if (!statement.moduleSpecifier) continue;
2185
+ if (!u.isStringLiteral(statement.moduleSpecifier)) continue;
2242
2186
  const moduleSpec = statement.moduleSpecifier.text;
2243
2187
  const exportClause = statement.exportClause;
2244
2188
  if (!exportClause) {
@@ -2256,12 +2200,10 @@ function resolveComponentSourcePath(componentName, context) {
2256
2200
  }
2257
2201
  }
2258
2202
  for (const moduleSpec of starReexportModules) {
2259
- if (!moduleSpec.startsWith("."))
2260
- continue;
2203
+ if (!moduleSpec.startsWith(".")) continue;
2261
2204
  const resolvedBase = path.resolve(path.dirname(sourceEntry), moduleSpec);
2262
2205
  const resolvedPath = resolveModulePath(resolvedBase);
2263
- if (!resolvedPath || !resolvedPath.endsWith(".ts"))
2264
- continue;
2206
+ if (!resolvedPath || !resolvedPath.endsWith(".ts")) continue;
2265
2207
  try {
2266
2208
  const modSource = fs.readFileSync(resolvedPath, "utf-8");
2267
2209
  const modFile = u.createSourceFile(
@@ -2294,16 +2236,12 @@ function resolveContractPath(contract, context) {
2294
2236
  }
2295
2237
  async function checkComponentContractConsistency(contract, context, result) {
2296
2238
  const componentName = contract.component;
2297
- if (!componentName)
2298
- return;
2239
+ if (!componentName) return;
2299
2240
  const sourcePath = resolveComponentSourcePath(componentName, context);
2300
- if (!sourcePath)
2301
- return;
2302
- if (!sourcePath.endsWith(".ts"))
2303
- return;
2241
+ if (!sourcePath) return;
2242
+ if (!sourcePath.endsWith(".ts")) return;
2304
2243
  const contractPath = resolveContractPath(contract, context);
2305
- if (!contractPath)
2306
- return;
2244
+ if (!contractPath) return;
2307
2245
  let contractContent;
2308
2246
  try {
2309
2247
  contractContent = await fs.promises.readFile(contractPath, "utf-8");
@@ -2311,8 +2249,7 @@ async function checkComponentContractConsistency(contract, context, result) {
2311
2249
  return;
2312
2250
  }
2313
2251
  const parsed = parseContract(contractContent, path.basename(contractPath));
2314
- if (parsed.validations.length > 0)
2315
- return;
2252
+ if (parsed.validations.length > 0) return;
2316
2253
  let sourceCode;
2317
2254
  try {
2318
2255
  sourceCode = await fs.promises.readFile(sourcePath, "utf-8");
@@ -2431,8 +2368,7 @@ async function validatePackageJson(context, result) {
2431
2368
  }
2432
2369
  async function validateDynamicContracts(context, result) {
2433
2370
  const { dynamic_contracts } = context.manifest;
2434
- if (!dynamic_contracts)
2435
- return;
2371
+ if (!dynamic_contracts) return;
2436
2372
  const dynamicConfigs = Array.isArray(dynamic_contracts) ? dynamic_contracts : [dynamic_contracts];
2437
2373
  for (const config of dynamicConfigs) {
2438
2374
  const prefix = config.prefix || "(unknown)";
@@ -2511,8 +2447,7 @@ function extractExpressions(text) {
2511
2447
  function extractTagPath(expr) {
2512
2448
  let cleaned = expr.replace(/^!/, "").trim();
2513
2449
  cleaned = cleaned.split(/\s*[!=]==?\s*/)[0].trim();
2514
- if (cleaned === "." || cleaned === "")
2515
- return null;
2450
+ if (cleaned === "." || cleaned === "") return null;
2516
2451
  if (/^[a-zA-Z_$][a-zA-Z0-9_$]*(\.[a-zA-Z_$][a-zA-Z0-9_$]*)*$/.test(cleaned)) {
2517
2452
  return cleaned;
2518
2453
  }
@@ -2611,8 +2546,7 @@ function collectUsedTags(jayHtml) {
2611
2546
  const ifVal = element.getAttribute?.("if");
2612
2547
  if (ifVal) {
2613
2548
  const ifPath = extractTagPath(ifVal);
2614
- if (ifPath)
2615
- resolvePath(ifPath, scopes);
2549
+ if (ifPath) resolvePath(ifPath, scopes);
2616
2550
  }
2617
2551
  const refVal = element.getAttribute?.("ref");
2618
2552
  if (refVal) {
@@ -2620,12 +2554,10 @@ function collectUsedTags(jayHtml) {
2620
2554
  }
2621
2555
  const attrs = element.attributes ?? {};
2622
2556
  for (const [name, value] of Object.entries(attrs)) {
2623
- if (SKIP_ATTRS.has(name))
2624
- continue;
2557
+ if (SKIP_ATTRS.has(name)) continue;
2625
2558
  for (const expr of extractExpressions(value)) {
2626
2559
  const p = extractTagPath(expr);
2627
- if (p)
2628
- resolvePath(p, scopes);
2560
+ if (p) resolvePath(p, scopes);
2629
2561
  }
2630
2562
  }
2631
2563
  for (const child of element.childNodes ?? []) {
@@ -2633,8 +2565,7 @@ function collectUsedTags(jayHtml) {
2633
2565
  const text = child.rawText ?? child.text ?? "";
2634
2566
  for (const expr of extractExpressions(text)) {
2635
2567
  const p = extractTagPath(expr);
2636
- if (p)
2637
- resolvePath(p, childScopes);
2568
+ if (p) resolvePath(p, childScopes);
2638
2569
  }
2639
2570
  } else if (child.nodeType === 1) {
2640
2571
  walkElement(child, childScopes);
@@ -2647,14 +2578,12 @@ function collectUsedTags(jayHtml) {
2647
2578
  function analyzeTagCoverage(jayHtml, file) {
2648
2579
  const imports = jayHtml.headlessImports;
2649
2580
  const withContracts = imports.filter((imp) => imp.contract);
2650
- if (withContracts.length === 0)
2651
- return null;
2581
+ if (withContracts.length === 0) return null;
2652
2582
  const usedTagsMap = collectUsedTags(jayHtml);
2653
2583
  const contracts = [];
2654
2584
  for (let i = 0; i < imports.length; i++) {
2655
2585
  const imp = imports[i];
2656
- if (!imp.contract)
2657
- continue;
2586
+ if (!imp.contract) continue;
2658
2587
  const allTags = flattenContractTags(imp.contract.tags);
2659
2588
  const usedSet = usedTagsMap.get(i) ?? /* @__PURE__ */ new Set();
2660
2589
  const expanded = new Set(usedSet);
@@ -2683,12 +2612,9 @@ function resolveContractTag(contract, tagPath) {
2683
2612
  let tags = contract.tags;
2684
2613
  for (let i = 0; i < segments.length; i++) {
2685
2614
  const tag = tags.find((t) => t.tag === segments[i]);
2686
- if (!tag)
2687
- return void 0;
2688
- if (i === segments.length - 1)
2689
- return tag;
2690
- if (!tag.tags)
2691
- return void 0;
2615
+ if (!tag) return void 0;
2616
+ if (i === segments.length - 1) return tag;
2617
+ if (!tag.tags) return void 0;
2692
2618
  tags = tag.tags;
2693
2619
  }
2694
2620
  return void 0;
@@ -2720,17 +2646,13 @@ function checkRefElementTypes(jayHtml, file) {
2720
2646
  importIndex = scope.importIndex;
2721
2647
  tagPath = scope.prefix ? `${scope.prefix}.${refPath}` : refPath;
2722
2648
  }
2723
- if (importIndex === void 0)
2724
- return;
2649
+ if (importIndex === void 0) return;
2725
2650
  const imp = imports[importIndex];
2726
- if (!imp.contract)
2727
- return;
2651
+ if (!imp.contract) return;
2728
2652
  const contractTag = resolveContractTag(imp.contract, tagPath);
2729
- if (!contractTag || !contractTag.elementType)
2730
- return;
2653
+ if (!contractTag || !contractTag.elementType) return;
2731
2654
  const contractTypes = contractTag.elementType;
2732
- if (contractTypes.includes("HTMLElement"))
2733
- return;
2655
+ if (contractTypes.includes("HTMLElement")) return;
2734
2656
  if (!contractTypes.includes(ref.actualType)) {
2735
2657
  const label = imp.key ? `${imp.key}.${tagPath}` : tagPath;
2736
2658
  warnings.push(
@@ -2840,8 +2762,7 @@ function checkRouteParams(parsedFile, filePath, pagesBase) {
2840
2762
  collectParams(imp.contract.params);
2841
2763
  }
2842
2764
  }
2843
- if (requiredParams.size === 0)
2844
- return [];
2765
+ if (requiredParams.size === 0) return [];
2845
2766
  const routeParams = extractRouteParams(filePath, pagesBase);
2846
2767
  const headlessProps = extractHeadlessPropsParamNames(parsedFile);
2847
2768
  const availableParams = /* @__PURE__ */ new Set([...routeParams, ...headlessProps]);
@@ -2857,11 +2778,9 @@ function checkRouteParams(parsedFile, filePath, pagesBase) {
2857
2778
  }
2858
2779
  function checkRouteToContractParams(parsedFile, filePath, pagesBase) {
2859
2780
  const routeParams = extractRouteParams(filePath, pagesBase);
2860
- if (routeParams.size === 0)
2861
- return [];
2781
+ if (routeParams.size === 0) return [];
2862
2782
  const hasAnyContract = !!parsedFile.contract || parsedFile.headlessImports.some((imp) => !!imp.contract);
2863
- if (!hasAnyContract)
2864
- return [];
2783
+ if (!hasAnyContract) return [];
2865
2784
  const declaredParams = /* @__PURE__ */ new Set();
2866
2785
  if (parsedFile.contract?.params) {
2867
2786
  for (const p of parsedFile.contract.params) {
@@ -2913,17 +2832,14 @@ function resolveBindingPhase(bindingPath, jayHtml) {
2913
2832
  const keyedImport = jayHtml.headlessImports.find((i) => i.key === root && i.contract);
2914
2833
  if (keyedImport?.contract) {
2915
2834
  const tagPath = segments.slice(1).join(".");
2916
- if (!tagPath)
2917
- return void 0;
2835
+ if (!tagPath) return void 0;
2918
2836
  const tag = resolveContractTag(keyedImport.contract, tagPath);
2919
- if (!tag)
2920
- return void 0;
2837
+ if (!tag) return void 0;
2921
2838
  return tag.phase || "slow";
2922
2839
  }
2923
2840
  if (jayHtml.contract) {
2924
2841
  const tag = resolveContractTag(jayHtml.contract, bindingPath);
2925
- if (!tag)
2926
- return void 0;
2842
+ if (!tag) return void 0;
2927
2843
  return tag.phase || "slow";
2928
2844
  }
2929
2845
  return void 0;
@@ -2974,15 +2890,12 @@ function checkHeadlessInstanceProps(jayHtml, file) {
2974
2890
  }
2975
2891
  for (const contractProp of contract.props) {
2976
2892
  const attrValue = lowerAttrs[contractProp.name.toLowerCase()];
2977
- if (!attrValue)
2978
- continue;
2893
+ if (!attrValue) continue;
2979
2894
  const bindingMatch = attrValue.match(/^\{(.+)\}$/);
2980
- if (!bindingMatch)
2981
- continue;
2895
+ if (!bindingMatch) continue;
2982
2896
  const bindingPath = bindingMatch[1];
2983
2897
  const sourcePhase = resolveBindingPhase(bindingPath, jayHtml);
2984
- if (!sourcePhase)
2985
- continue;
2898
+ if (!sourcePhase) continue;
2986
2899
  const propPhase = contractProp.phase ?? "slow";
2987
2900
  const sourceOrder = PHASE_ORDER[sourcePhase] ?? 0;
2988
2901
  const propOrder = PHASE_ORDER[propPhase] ?? 0;
@@ -3020,8 +2933,7 @@ function resolveLinkedTags(tags, contractDir) {
3020
2933
  });
3021
2934
  }
3022
2935
  function resolveContractLinks(contract, contractPath) {
3023
- if (!contractPath)
3024
- return contract;
2936
+ if (!contractPath) return contract;
3025
2937
  const contractDir = path.dirname(contractPath);
3026
2938
  return { ...contract, tags: resolveLinkedTags(contract.tags, contractDir) };
3027
2939
  }
@@ -3029,8 +2941,7 @@ async function runPluginValidators(projectRoot, parsedFiles, errors, warnings) {
3029
2941
  const scannedPlugins = await scanPlugins({ projectRoot, includeDevDeps: true });
3030
2942
  const loadedValidators = [];
3031
2943
  for (const [, plugin] of scannedPlugins) {
3032
- if (!plugin.manifest.validators)
3033
- continue;
2944
+ if (!plugin.manifest.validators) continue;
3034
2945
  for (const validatorDef of plugin.manifest.validators) {
3035
2946
  const source = `${plugin.name}/${validatorDef.name}`;
3036
2947
  let validatorFn;
@@ -3609,8 +3520,7 @@ async function ensureAgentKitDocs(projectRoot, _force, mode) {
3609
3520
  const sharedDirs = ["contracts"];
3610
3521
  for (const dir of sharedDirs) {
3611
3522
  const srcDir = path$1.join(templateDir, dir);
3612
- if (!fsSync.existsSync(srcDir))
3613
- continue;
3523
+ if (!fsSync.existsSync(srcDir)) continue;
3614
3524
  await copyDirRecursive(srcDir, path$1.join(agentKitDir, dir));
3615
3525
  getLogger().info(chalk.gray(` Created agent-kit/${dir}/`));
3616
3526
  }
@@ -3635,8 +3545,7 @@ async function mergePluginAgentKitGuides(projectRoot, mode) {
3635
3545
  const copiedPerRole = /* @__PURE__ */ new Map();
3636
3546
  for (const [, plugin] of plugins) {
3637
3547
  const pluginAgentKitDir = path$1.join(plugin.pluginPath, "agent-kit");
3638
- if (!fsSync.existsSync(pluginAgentKitDir))
3639
- continue;
3548
+ if (!fsSync.existsSync(pluginAgentKitDir)) continue;
3640
3549
  for (const role of roles) {
3641
3550
  const roleSourceDir = path$1.join(pluginAgentKitDir, role);
3642
3551
  let files;
@@ -3647,8 +3556,7 @@ async function mergePluginAgentKitGuides(projectRoot, mode) {
3647
3556
  } catch {
3648
3557
  continue;
3649
3558
  }
3650
- if (files.length === 0)
3651
- continue;
3559
+ if (files.length === 0) continue;
3652
3560
  const roleOutputDir = path$1.join(agentKitDir, role);
3653
3561
  await fs$1.mkdir(roleOutputDir, { recursive: true });
3654
3562
  for (const filename of files) {
@@ -3671,8 +3579,7 @@ async function mergePluginAgentKitGuides(projectRoot, mode) {
3671
3579
  }
3672
3580
  } catch {
3673
3581
  }
3674
- if (!copiedPerRole.has(role))
3675
- copiedPerRole.set(role, []);
3582
+ if (!copiedPerRole.has(role)) copiedPerRole.set(role, []);
3676
3583
  copiedPerRole.get(role).push({ filename, pluginName: plugin.name, description });
3677
3584
  getLogger().info(
3678
3585
  chalk.gray(
@@ -3684,8 +3591,7 @@ async function mergePluginAgentKitGuides(projectRoot, mode) {
3684
3591
  }
3685
3592
  for (const [role, entries] of copiedPerRole) {
3686
3593
  const instructionsPath = path$1.join(agentKitDir, role, "INSTRUCTIONS.md");
3687
- if (!fsSync.existsSync(instructionsPath))
3688
- continue;
3594
+ if (!fsSync.existsSync(instructionsPath)) continue;
3689
3595
  const lines = [
3690
3596
  "",
3691
3597
  "## Plugin-Contributed Guides",
@@ -3707,8 +3613,7 @@ async function generatePluginAgentKit(projectRoot, options, initErrors, viteServ
3707
3613
  verbose: options.verbose,
3708
3614
  pluginFilter: options.plugin
3709
3615
  });
3710
- if (plugins.length === 0)
3711
- return;
3616
+ if (plugins.length === 0) return;
3712
3617
  const logger = getLogger();
3713
3618
  logger.important("");
3714
3619
  logger.important(chalk.bold("Generating plugin agent-kit data..."));
@@ -3937,20 +3842,17 @@ function createAnswersFilePrompt(answers, pluginName) {
3937
3842
  return {
3938
3843
  async input(options) {
3939
3844
  const value = answers[options.key];
3940
- if (value !== void 0)
3941
- return value;
3845
+ if (value !== void 0) return value;
3942
3846
  throw new SetupNeedsAnswerError(pluginName, options.key, "input", options.message);
3943
3847
  },
3944
3848
  async confirm(options) {
3945
3849
  const value = answers[options.key];
3946
- if (value !== void 0)
3947
- return value === "true" || value === "yes";
3850
+ if (value !== void 0) return value === "true" || value === "yes";
3948
3851
  throw new SetupNeedsAnswerError(pluginName, options.key, "confirm", options.message);
3949
3852
  },
3950
3853
  async select(options) {
3951
3854
  const value = answers[options.key];
3952
- if (value !== void 0)
3953
- return value;
3855
+ if (value !== void 0) return value;
3954
3856
  throw new SetupNeedsAnswerError(
3955
3857
  pluginName,
3956
3858
  options.key,
@@ -4111,12 +4013,9 @@ async function runSetup(pluginFilter, options, projectRoot) {
4111
4013
  }
4112
4014
  await runProjectInit(projectRoot, viteServer);
4113
4015
  const parts = [];
4114
- if (configured > 0)
4115
- parts.push(`${configured} configured`);
4116
- if (needsConfig > 0)
4117
- parts.push(`${needsConfig} needs config`);
4118
- if (errors > 0)
4119
- parts.push(`${errors} error(s)`);
4016
+ if (configured > 0) parts.push(`${configured} configured`);
4017
+ if (needsConfig > 0) parts.push(`${needsConfig} needs config`);
4018
+ if (errors > 0) parts.push(`${errors} error(s)`);
4120
4019
  logger.important(`Setup complete: ${parts.join(", ")}`);
4121
4020
  if (errors > 0) {
4122
4021
  process.exit(1);
@@ -4135,8 +4034,7 @@ async function runSetup(pluginFilter, options, projectRoot) {
4135
4034
  }
4136
4035
  async function initPlugin(pluginName, allPluginsWithInit, viteServer, logger) {
4137
4036
  const pluginInit = allPluginsWithInit.filter((p) => p.name === pluginName);
4138
- if (pluginInit.length === 0)
4139
- return;
4037
+ if (pluginInit.length === 0) return;
4140
4038
  const initErrors = await executePluginServerInits(pluginInit, viteServer, false, true);
4141
4039
  if (initErrors.size > 0) {
4142
4040
  for (const [, err] of initErrors) {
@@ -4276,8 +4174,7 @@ function printCommandList(commands) {
4276
4174
  logger.important("\nAvailable plugin commands:\n");
4277
4175
  const byPlugin = /* @__PURE__ */ new Map();
4278
4176
  for (const cmd of commands) {
4279
- if (!byPlugin.has(cmd.pluginName))
4280
- byPlugin.set(cmd.pluginName, []);
4177
+ if (!byPlugin.has(cmd.pluginName)) byPlugin.set(cmd.pluginName, []);
4281
4178
  byPlugin.get(cmd.pluginName).push(cmd);
4282
4179
  }
4283
4180
  for (const [pluginName, cmds] of byPlugin) {
@@ -4333,8 +4230,7 @@ program.command("build").description("Build production artifacts").option("-p, -
4333
4230
  await runBuild(options.path, options);
4334
4231
  } catch (error) {
4335
4232
  getLogger().error(chalk.red("Build failed:") + " " + error.message);
4336
- if (error.stack)
4337
- getLogger().error(error.stack);
4233
+ if (error.stack) getLogger().error(error.stack);
4338
4234
  process.exit(1);
4339
4235
  }
4340
4236
  });
@@ -4343,8 +4239,7 @@ program.command("serve").description("Start production server").option("-p, --pa
4343
4239
  await runServe(options.path, options);
4344
4240
  } catch (error) {
4345
4241
  getLogger().error(chalk.red("Server failed:") + " " + error.message);
4346
- if (error.stack)
4347
- getLogger().error(error.stack);
4242
+ if (error.stack) getLogger().error(error.stack);
4348
4243
  process.exit(1);
4349
4244
  }
4350
4245
  });
@@ -4353,8 +4248,7 @@ program.command("rebuild").description("Rebuild instances by contract, route, or
4353
4248
  await runRebuild(options.path, options);
4354
4249
  } catch (error) {
4355
4250
  getLogger().error(chalk.red("Rebuild failed:") + " " + error.message);
4356
- if (error.stack)
4357
- getLogger().error(error.stack);
4251
+ if (error.stack) getLogger().error(error.stack);
4358
4252
  process.exit(1);
4359
4253
  }
4360
4254
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jay-framework/jay-stack-cli",
3
- "version": "0.23.0",
3
+ "version": "0.23.1",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -25,14 +25,14 @@
25
25
  },
26
26
  "dependencies": {
27
27
  "@inquirer/prompts": "^8.5.2",
28
- "@jay-framework/compiler-jay-html": "^0.23.0",
29
- "@jay-framework/compiler-shared": "^0.23.0",
30
- "@jay-framework/dev-server": "^0.23.0",
31
- "@jay-framework/fullstack-component": "^0.23.0",
32
- "@jay-framework/logger": "^0.23.0",
33
- "@jay-framework/plugin-validator": "^0.23.0",
34
- "@jay-framework/production-server": "^0.23.0",
35
- "@jay-framework/stack-server-runtime": "^0.23.0",
28
+ "@jay-framework/compiler-jay-html": "^0.23.1",
29
+ "@jay-framework/compiler-shared": "^0.23.1",
30
+ "@jay-framework/dev-server": "^0.23.1",
31
+ "@jay-framework/fullstack-component": "^0.23.1",
32
+ "@jay-framework/logger": "^0.23.1",
33
+ "@jay-framework/plugin-validator": "^0.23.1",
34
+ "@jay-framework/production-server": "^0.23.1",
35
+ "@jay-framework/stack-server-runtime": "^0.23.1",
36
36
  "chalk": "^4.1.2",
37
37
  "commander": "^14.0.0",
38
38
  "express": "^5.0.1",
@@ -43,7 +43,7 @@
43
43
  "yaml": "^2.3.4"
44
44
  },
45
45
  "devDependencies": {
46
- "@jay-framework/dev-environment": "^0.23.0",
46
+ "@jay-framework/dev-environment": "^0.23.1",
47
47
  "@types/express": "^5.0.2",
48
48
  "@types/node": "^22.15.21",
49
49
  "nodemon": "^3.0.3",