@jay-framework/jay-stack-cli 0.18.4 → 0.19.0

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.
Files changed (2) hide show
  1. package/dist/index.js +108 -51
  2. package/package.json +11 -11
package/dist/index.js CHANGED
@@ -8,7 +8,7 @@ import path from "path";
8
8
  import fs, { promises } from "fs";
9
9
  import YAML from "yaml";
10
10
  import { getLogger, setDevLogger, createDevLogger } from "@jay-framework/logger";
11
- import { parseJayFile, JAY_IMPORT_RESOLVER, generateElementDefinitionFile, ContractTagType, parseContract, generateElementFile, generateServerElementFile, htmlElementTagNameMap } from "@jay-framework/compiler-jay-html";
11
+ import { parseJayFile, JAY_IMPORT_RESOLVER, generateElementDefinitionFile, ContractTagType, parseContract, generateElementFile, generateServerElementFile, htmlElementTagNameMap, loadLinkedContract, getLinkedContractDir } from "@jay-framework/compiler-jay-html";
12
12
  import { JAY_CONTRACT_EXTENSION, JAY_EXTENSION, resolvePluginManifest, LOCAL_PLUGIN_PATH, JayAtomicType, JayEnumType, loadPluginManifest, RuntimeMode, GenerateTarget } from "@jay-framework/compiler-shared";
13
13
  import { scanPlugins as scanPlugins$1, listContracts, materializeContracts } from "@jay-framework/stack-server-runtime";
14
14
  import { listContracts as listContracts2, materializeContracts as materializeContracts2 } from "@jay-framework/stack-server-runtime";
@@ -4266,17 +4266,44 @@ function checkHeadlessInstanceProps(jayHtml, file) {
4266
4266
  walkElement(jayHtml.body);
4267
4267
  return warnings;
4268
4268
  }
4269
+ function resolveLinkedTags(tags, contractDir) {
4270
+ return tags.map((tag) => {
4271
+ if (tag.link) {
4272
+ const linked = loadLinkedContract(tag.link, contractDir, JAY_IMPORT_RESOLVER);
4273
+ if (linked) {
4274
+ const childDir = getLinkedContractDir(tag.link, contractDir, JAY_IMPORT_RESOLVER);
4275
+ return { ...tag, tags: resolveLinkedTags(linked.tags, childDir) };
4276
+ }
4277
+ }
4278
+ if (tag.tags) {
4279
+ return { ...tag, tags: resolveLinkedTags(tag.tags, contractDir) };
4280
+ }
4281
+ return tag;
4282
+ });
4283
+ }
4284
+ function resolveContractLinks(contract, contractPath) {
4285
+ if (!contractPath)
4286
+ return contract;
4287
+ const contractDir = path.dirname(contractPath);
4288
+ return { ...contract, tags: resolveLinkedTags(contract.tags, contractDir) };
4289
+ }
4269
4290
  async function runPluginValidators(projectRoot, parsedFiles, errors, warnings) {
4270
- const scannedPlugins = await scanPlugins$1({ projectRoot });
4291
+ const scannedPlugins = await scanPlugins$1({ projectRoot, includeDevDeps: true });
4292
+ const loadedValidators = [];
4271
4293
  for (const [, plugin] of scannedPlugins) {
4272
4294
  if (!plugin.manifest.validators)
4273
4295
  continue;
4274
4296
  for (const validatorDef of plugin.manifest.validators) {
4275
4297
  let validatorFn;
4276
4298
  try {
4277
- const handlerPath = path.resolve(plugin.pluginPath, validatorDef.handler);
4278
- const handlerModule = await import(handlerPath);
4279
- validatorFn = handlerModule.validate;
4299
+ let handlerModule;
4300
+ if (plugin.isLocal) {
4301
+ const handlerPath = path.resolve(plugin.pluginPath, validatorDef.handler);
4302
+ handlerModule = await import(handlerPath);
4303
+ } else {
4304
+ handlerModule = await import(plugin.packageName);
4305
+ }
4306
+ validatorFn = plugin.isLocal ? handlerModule.validate ?? handlerModule.default : handlerModule[validatorDef.handler];
4280
4307
  if (typeof validatorFn !== "function") {
4281
4308
  errors.push({
4282
4309
  file: `plugin:${plugin.name}`,
@@ -4294,26 +4321,32 @@ async function runPluginValidators(projectRoot, parsedFiles, errors, warnings) {
4294
4321
  continue;
4295
4322
  }
4296
4323
  const source = `${plugin.name}/${validatorDef.name}`;
4324
+ loadedValidators.push(source);
4297
4325
  for (const { relativePath, parsed } of parsedFiles) {
4326
+ const pageContractPath = parsed.contractRef ? path.resolve(path.dirname(path.resolve(projectRoot, relativePath)), parsed.contractRef) : void 0;
4327
+ const resolvedPageContract = parsed.contract ? resolveContractLinks(parsed.contract, pageContractPath) : void 0;
4298
4328
  const ctx = {
4299
4329
  filePath: relativePath,
4300
4330
  body: parsed.body,
4301
- contract: parsed.contract ? {
4302
- name: parsed.contract.name,
4303
- tags: parsed.contract.tags,
4304
- props: parsed.contract.props,
4305
- params: parsed.contract.params
4331
+ contract: resolvedPageContract ? {
4332
+ name: resolvedPageContract.name,
4333
+ tags: resolvedPageContract.tags,
4334
+ props: resolvedPageContract.props,
4335
+ params: resolvedPageContract.params
4306
4336
  } : void 0,
4307
- headlessImports: parsed.headlessImports.map((imp) => ({
4308
- key: imp.key,
4309
- contractName: imp.contractName,
4310
- contract: imp.contract ? {
4311
- name: imp.contract.name,
4312
- tags: imp.contract.tags,
4313
- props: imp.contract.props,
4314
- params: imp.contract.params
4315
- } : void 0
4316
- })),
4337
+ headlessImports: parsed.headlessImports.map((imp) => {
4338
+ const resolvedContract = imp.contract ? resolveContractLinks(imp.contract, imp.contractPath) : void 0;
4339
+ return {
4340
+ key: imp.key,
4341
+ contractName: imp.contractName,
4342
+ contract: resolvedContract ? {
4343
+ name: resolvedContract.name,
4344
+ tags: resolvedContract.tags,
4345
+ props: resolvedContract.props,
4346
+ params: resolvedContract.params
4347
+ } : void 0
4348
+ };
4349
+ }),
4317
4350
  projectRoot
4318
4351
  };
4319
4352
  try {
@@ -4347,6 +4380,7 @@ async function runPluginValidators(projectRoot, parsedFiles, errors, warnings) {
4347
4380
  }
4348
4381
  }
4349
4382
  }
4383
+ return loadedValidators;
4350
4384
  }
4351
4385
  async function validateJayFiles(options = {}) {
4352
4386
  const config = loadConfig();
@@ -4487,14 +4521,15 @@ async function validateJayFiles(options = {}) {
4487
4521
  }
4488
4522
  }
4489
4523
  }
4490
- await runPluginValidators(projectRoot, parsedFiles, errors, warnings);
4524
+ const pluginValidators = await runPluginValidators(projectRoot, parsedFiles, errors, warnings);
4491
4525
  return {
4492
4526
  valid: errors.length === 0,
4493
4527
  jayHtmlFilesScanned: jayHtmlFiles.length,
4494
4528
  contractFilesScanned: contractFiles.length,
4495
4529
  errors,
4496
4530
  warnings,
4497
- coverage
4531
+ coverage,
4532
+ pluginValidators
4498
4533
  };
4499
4534
  }
4500
4535
  function printJayValidationResult(result, options) {
@@ -4504,65 +4539,87 @@ function printJayValidationResult(result, options) {
4504
4539
  return;
4505
4540
  }
4506
4541
  logger.important("");
4507
- if (result.valid) {
4508
- logger.important(chalk.green("✅ Jay Stack validation successful!\n"));
4542
+ const coreErrors = result.errors.filter((e2) => e2.stage !== "plugin");
4543
+ const coreWarnings = result.warnings.filter((w) => !w.source);
4544
+ logger.important(chalk.bold("📦 jay-stack (core)"));
4545
+ if (coreErrors.length === 0) {
4509
4546
  logger.important(
4510
- `Scanned ${result.jayHtmlFilesScanned} .jay-html files, ${result.contractFilesScanned} .jay-contract files`
4547
+ chalk.green(
4548
+ ` ✅ ${result.jayHtmlFilesScanned} .jay-html files, ${result.contractFilesScanned} .jay-contract files — no errors`
4549
+ )
4511
4550
  );
4512
- logger.important("No errors found.");
4513
4551
  } else {
4514
- logger.important(chalk.red("❌ Jay Stack validation failed\n"));
4515
- logger.important("Errors:");
4516
- for (const error of result.errors) {
4517
- const prefix = error.source ? `[${error.source}] ` : "";
4518
- logger.important(chalk.red(` ❌ ${error.file}`));
4519
- logger.important(chalk.gray(` ${prefix}${error.message}`));
4552
+ for (const error of coreErrors) {
4553
+ logger.important(chalk.red(` ❌ ${error.file}`));
4554
+ logger.important(chalk.gray(` ${error.message}`));
4520
4555
  if (error.suggestion) {
4521
- logger.important(chalk.blue(` Suggestion: ${error.suggestion}`));
4556
+ logger.important(chalk.blue(` Suggestion: ${error.suggestion}`));
4522
4557
  }
4523
- logger.important("");
4524
4558
  }
4525
- const validFiles = result.jayHtmlFilesScanned + result.contractFilesScanned - result.errors.length;
4526
- logger.important(
4527
- chalk.red(`${result.errors.length} error(s) found, ${validFiles} file(s) valid.`)
4528
- );
4529
4559
  }
4530
- if (result.warnings.length > 0) {
4560
+ for (const warning of coreWarnings) {
4561
+ logger.important(chalk.yellow(` ⚠ ${warning.file}`));
4562
+ logger.important(chalk.gray(` ${warning.message}`));
4563
+ if (warning.suggestion) {
4564
+ logger.important(chalk.blue(` Suggestion: ${warning.suggestion}`));
4565
+ }
4566
+ }
4567
+ const pluginErrors = result.errors.filter((e2) => e2.stage === "plugin");
4568
+ const pluginWarnings = result.warnings.filter((w) => !!w.source);
4569
+ for (const validatorName of result.pluginValidators) {
4570
+ const errs = pluginErrors.filter((e2) => e2.source === validatorName);
4571
+ const warns = pluginWarnings.filter((w) => w.source === validatorName);
4531
4572
  logger.important("");
4532
- logger.important(chalk.yellow("Warnings:"));
4533
- for (const warning of result.warnings) {
4534
- const prefix = warning.source ? `[${warning.source}] ` : "";
4535
- logger.important(chalk.yellow(` ⚠ ${warning.file}`));
4536
- logger.important(chalk.gray(` ${prefix}${warning.message}`));
4573
+ logger.important(chalk.bold(`📦 ${validatorName}`));
4574
+ if (errs.length === 0 && warns.length === 0) {
4575
+ logger.important(chalk.green(" ✅ No issues found"));
4576
+ }
4577
+ for (const error of errs) {
4578
+ logger.important(chalk.red(` ❌ ${error.file}`));
4579
+ logger.important(chalk.gray(` ${error.message}`));
4580
+ if (error.suggestion) {
4581
+ logger.important(chalk.blue(` Suggestion: ${error.suggestion}`));
4582
+ }
4583
+ }
4584
+ for (const warning of warns) {
4585
+ logger.important(chalk.yellow(` ⚠ ${warning.file}`));
4586
+ logger.important(chalk.gray(` ${warning.message}`));
4537
4587
  if (warning.suggestion) {
4538
- logger.important(chalk.blue(` Suggestion: ${warning.suggestion}`));
4588
+ logger.important(chalk.blue(` Suggestion: ${warning.suggestion}`));
4539
4589
  }
4540
- logger.important("");
4541
4590
  }
4542
4591
  }
4543
4592
  if (result.coverage.length > 0) {
4544
4593
  logger.important("");
4545
- logger.important("Tag Coverage:");
4594
+ logger.important(chalk.bold("📦 Tag Coverage"));
4546
4595
  for (const fileCov of result.coverage) {
4547
- logger.important(` ${fileCov.file}`);
4596
+ logger.important(` ${fileCov.file}`);
4548
4597
  for (const contract of fileCov.contracts) {
4549
4598
  const label = contract.key ? `${contract.key} (${contract.contractName})` : contract.contractName;
4550
4599
  logger.important(
4551
- ` ${label}: ${contract.usedTags}/${contract.totalTags} tags used`
4600
+ ` ${label}: ${contract.usedTags}/${contract.totalTags} tags used`
4552
4601
  );
4553
4602
  if (contract.unusedTags.length > 0) {
4554
- logger.important(chalk.gray(` Unused: ${contract.unusedTags.join(", ")}`));
4603
+ logger.important(
4604
+ chalk.gray(` Unused: ${contract.unusedTags.join(", ")}`)
4605
+ );
4555
4606
  }
4556
4607
  if (contract.requiredUnusedTags.length > 0) {
4557
4608
  logger.important(
4558
4609
  chalk.yellow(
4559
- ` ⚠ Required unused: ${contract.requiredUnusedTags.join(", ")}`
4610
+ ` ⚠ Required unused: ${contract.requiredUnusedTags.join(", ")}`
4560
4611
  )
4561
4612
  );
4562
4613
  }
4563
4614
  }
4564
4615
  }
4565
4616
  }
4617
+ logger.important("");
4618
+ if (result.valid) {
4619
+ logger.important(chalk.green("Validation passed."));
4620
+ } else {
4621
+ logger.important(chalk.red(`Validation failed — ${result.errors.length} error(s).`));
4622
+ }
4566
4623
  }
4567
4624
  async function runValidate(scanPath, options) {
4568
4625
  const result = await validateJayFiles({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jay-framework/jay-stack-cli",
3
- "version": "0.18.4",
3
+ "version": "0.19.0",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -24,15 +24,15 @@
24
24
  "test:watch": "vitest"
25
25
  },
26
26
  "dependencies": {
27
- "@jay-framework/compiler-jay-html": "^0.18.4",
28
- "@jay-framework/compiler-shared": "^0.18.4",
29
- "@jay-framework/dev-server": "^0.18.4",
30
- "@jay-framework/editor-server": "^0.18.4",
31
- "@jay-framework/fullstack-component": "^0.18.4",
32
- "@jay-framework/logger": "^0.18.4",
33
- "@jay-framework/plugin-validator": "^0.18.4",
34
- "@jay-framework/production-server": "^0.18.4",
35
- "@jay-framework/stack-server-runtime": "^0.18.4",
27
+ "@jay-framework/compiler-jay-html": "^0.19.0",
28
+ "@jay-framework/compiler-shared": "^0.19.0",
29
+ "@jay-framework/dev-server": "^0.19.0",
30
+ "@jay-framework/editor-server": "^0.19.0",
31
+ "@jay-framework/fullstack-component": "^0.19.0",
32
+ "@jay-framework/logger": "^0.19.0",
33
+ "@jay-framework/plugin-validator": "^0.19.0",
34
+ "@jay-framework/production-server": "^0.19.0",
35
+ "@jay-framework/stack-server-runtime": "^0.19.0",
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.18.4",
46
+ "@jay-framework/dev-environment": "^0.19.0",
47
47
  "@types/express": "^5.0.2",
48
48
  "@types/node": "^22.15.21",
49
49
  "nodemon": "^3.0.3",