@jay-framework/jay-stack-cli 0.18.4 → 0.19.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.
Files changed (2) hide show
  1. package/dist/index.js +111 -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,35 @@ 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(
4327
+ path.dirname(path.resolve(projectRoot, relativePath)),
4328
+ parsed.contractRef
4329
+ ) : void 0;
4330
+ const resolvedPageContract = parsed.contract ? resolveContractLinks(parsed.contract, pageContractPath) : void 0;
4298
4331
  const ctx = {
4299
4332
  filePath: relativePath,
4300
4333
  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
4334
+ contract: resolvedPageContract ? {
4335
+ name: resolvedPageContract.name,
4336
+ tags: resolvedPageContract.tags,
4337
+ props: resolvedPageContract.props,
4338
+ params: resolvedPageContract.params
4306
4339
  } : 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
- })),
4340
+ headlessImports: parsed.headlessImports.map((imp) => {
4341
+ const resolvedContract = imp.contract ? resolveContractLinks(imp.contract, imp.contractPath) : void 0;
4342
+ return {
4343
+ key: imp.key,
4344
+ contractName: imp.contractName,
4345
+ contract: resolvedContract ? {
4346
+ name: resolvedContract.name,
4347
+ tags: resolvedContract.tags,
4348
+ props: resolvedContract.props,
4349
+ params: resolvedContract.params
4350
+ } : void 0
4351
+ };
4352
+ }),
4317
4353
  projectRoot
4318
4354
  };
4319
4355
  try {
@@ -4347,6 +4383,7 @@ async function runPluginValidators(projectRoot, parsedFiles, errors, warnings) {
4347
4383
  }
4348
4384
  }
4349
4385
  }
4386
+ return loadedValidators;
4350
4387
  }
4351
4388
  async function validateJayFiles(options = {}) {
4352
4389
  const config = loadConfig();
@@ -4487,14 +4524,15 @@ async function validateJayFiles(options = {}) {
4487
4524
  }
4488
4525
  }
4489
4526
  }
4490
- await runPluginValidators(projectRoot, parsedFiles, errors, warnings);
4527
+ const pluginValidators = await runPluginValidators(projectRoot, parsedFiles, errors, warnings);
4491
4528
  return {
4492
4529
  valid: errors.length === 0,
4493
4530
  jayHtmlFilesScanned: jayHtmlFiles.length,
4494
4531
  contractFilesScanned: contractFiles.length,
4495
4532
  errors,
4496
4533
  warnings,
4497
- coverage
4534
+ coverage,
4535
+ pluginValidators
4498
4536
  };
4499
4537
  }
4500
4538
  function printJayValidationResult(result, options) {
@@ -4504,65 +4542,87 @@ function printJayValidationResult(result, options) {
4504
4542
  return;
4505
4543
  }
4506
4544
  logger.important("");
4507
- if (result.valid) {
4508
- logger.important(chalk.green("✅ Jay Stack validation successful!\n"));
4545
+ const coreErrors = result.errors.filter((e2) => e2.stage !== "plugin");
4546
+ const coreWarnings = result.warnings.filter((w) => !w.source);
4547
+ logger.important(chalk.bold("📦 jay-stack (core)"));
4548
+ if (coreErrors.length === 0) {
4509
4549
  logger.important(
4510
- `Scanned ${result.jayHtmlFilesScanned} .jay-html files, ${result.contractFilesScanned} .jay-contract files`
4550
+ chalk.green(
4551
+ ` ✅ ${result.jayHtmlFilesScanned} .jay-html files, ${result.contractFilesScanned} .jay-contract files — no errors`
4552
+ )
4511
4553
  );
4512
- logger.important("No errors found.");
4513
4554
  } 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}`));
4555
+ for (const error of coreErrors) {
4556
+ logger.important(chalk.red(` ❌ ${error.file}`));
4557
+ logger.important(chalk.gray(` ${error.message}`));
4520
4558
  if (error.suggestion) {
4521
- logger.important(chalk.blue(` Suggestion: ${error.suggestion}`));
4559
+ logger.important(chalk.blue(` Suggestion: ${error.suggestion}`));
4522
4560
  }
4523
- logger.important("");
4524
4561
  }
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
4562
  }
4530
- if (result.warnings.length > 0) {
4563
+ for (const warning of coreWarnings) {
4564
+ logger.important(chalk.yellow(` ⚠ ${warning.file}`));
4565
+ logger.important(chalk.gray(` ${warning.message}`));
4566
+ if (warning.suggestion) {
4567
+ logger.important(chalk.blue(` Suggestion: ${warning.suggestion}`));
4568
+ }
4569
+ }
4570
+ const pluginErrors = result.errors.filter((e2) => e2.stage === "plugin");
4571
+ const pluginWarnings = result.warnings.filter((w) => !!w.source);
4572
+ for (const validatorName of result.pluginValidators) {
4573
+ const errs = pluginErrors.filter((e2) => e2.source === validatorName);
4574
+ const warns = pluginWarnings.filter((w) => w.source === validatorName);
4531
4575
  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}`));
4576
+ logger.important(chalk.bold(`📦 ${validatorName}`));
4577
+ if (errs.length === 0 && warns.length === 0) {
4578
+ logger.important(chalk.green(" ✅ No issues found"));
4579
+ }
4580
+ for (const error of errs) {
4581
+ logger.important(chalk.red(` ❌ ${error.file}`));
4582
+ logger.important(chalk.gray(` ${error.message}`));
4583
+ if (error.suggestion) {
4584
+ logger.important(chalk.blue(` Suggestion: ${error.suggestion}`));
4585
+ }
4586
+ }
4587
+ for (const warning of warns) {
4588
+ logger.important(chalk.yellow(` ⚠ ${warning.file}`));
4589
+ logger.important(chalk.gray(` ${warning.message}`));
4537
4590
  if (warning.suggestion) {
4538
- logger.important(chalk.blue(` Suggestion: ${warning.suggestion}`));
4591
+ logger.important(chalk.blue(` Suggestion: ${warning.suggestion}`));
4539
4592
  }
4540
- logger.important("");
4541
4593
  }
4542
4594
  }
4543
4595
  if (result.coverage.length > 0) {
4544
4596
  logger.important("");
4545
- logger.important("Tag Coverage:");
4597
+ logger.important(chalk.bold("📦 Tag Coverage"));
4546
4598
  for (const fileCov of result.coverage) {
4547
- logger.important(` ${fileCov.file}`);
4599
+ logger.important(` ${fileCov.file}`);
4548
4600
  for (const contract of fileCov.contracts) {
4549
4601
  const label = contract.key ? `${contract.key} (${contract.contractName})` : contract.contractName;
4550
4602
  logger.important(
4551
- ` ${label}: ${contract.usedTags}/${contract.totalTags} tags used`
4603
+ ` ${label}: ${contract.usedTags}/${contract.totalTags} tags used`
4552
4604
  );
4553
4605
  if (contract.unusedTags.length > 0) {
4554
- logger.important(chalk.gray(` Unused: ${contract.unusedTags.join(", ")}`));
4606
+ logger.important(
4607
+ chalk.gray(` Unused: ${contract.unusedTags.join(", ")}`)
4608
+ );
4555
4609
  }
4556
4610
  if (contract.requiredUnusedTags.length > 0) {
4557
4611
  logger.important(
4558
4612
  chalk.yellow(
4559
- ` ⚠ Required unused: ${contract.requiredUnusedTags.join(", ")}`
4613
+ ` ⚠ Required unused: ${contract.requiredUnusedTags.join(", ")}`
4560
4614
  )
4561
4615
  );
4562
4616
  }
4563
4617
  }
4564
4618
  }
4565
4619
  }
4620
+ logger.important("");
4621
+ if (result.valid) {
4622
+ logger.important(chalk.green("Validation passed."));
4623
+ } else {
4624
+ logger.important(chalk.red(`Validation failed — ${result.errors.length} error(s).`));
4625
+ }
4566
4626
  }
4567
4627
  async function runValidate(scanPath, options) {
4568
4628
  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.1",
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.1",
28
+ "@jay-framework/compiler-shared": "^0.19.1",
29
+ "@jay-framework/dev-server": "^0.19.1",
30
+ "@jay-framework/editor-server": "^0.19.1",
31
+ "@jay-framework/fullstack-component": "^0.19.1",
32
+ "@jay-framework/logger": "^0.19.1",
33
+ "@jay-framework/plugin-validator": "^0.19.1",
34
+ "@jay-framework/production-server": "^0.19.1",
35
+ "@jay-framework/stack-server-runtime": "^0.19.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.18.4",
46
+ "@jay-framework/dev-environment": "^0.19.1",
47
47
  "@types/express": "^5.0.2",
48
48
  "@types/node": "^22.15.21",
49
49
  "nodemon": "^3.0.3",