@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.
- package/dist/index.js +111 -51
- 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
|
-
|
|
4278
|
-
|
|
4279
|
-
|
|
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:
|
|
4302
|
-
name:
|
|
4303
|
-
tags:
|
|
4304
|
-
props:
|
|
4305
|
-
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
|
-
|
|
4309
|
-
|
|
4310
|
-
|
|
4311
|
-
|
|
4312
|
-
|
|
4313
|
-
|
|
4314
|
-
|
|
4315
|
-
|
|
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
|
-
|
|
4508
|
-
|
|
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
|
-
|
|
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
|
-
|
|
4515
|
-
|
|
4516
|
-
|
|
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(`
|
|
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
|
-
|
|
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.
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
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(`
|
|
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(`
|
|
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
|
-
`
|
|
4603
|
+
` ${label}: ${contract.usedTags}/${contract.totalTags} tags used`
|
|
4552
4604
|
);
|
|
4553
4605
|
if (contract.unusedTags.length > 0) {
|
|
4554
|
-
logger.important(
|
|
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
|
-
`
|
|
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.
|
|
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.
|
|
28
|
-
"@jay-framework/compiler-shared": "^0.
|
|
29
|
-
"@jay-framework/dev-server": "^0.
|
|
30
|
-
"@jay-framework/editor-server": "^0.
|
|
31
|
-
"@jay-framework/fullstack-component": "^0.
|
|
32
|
-
"@jay-framework/logger": "^0.
|
|
33
|
-
"@jay-framework/plugin-validator": "^0.
|
|
34
|
-
"@jay-framework/production-server": "^0.
|
|
35
|
-
"@jay-framework/stack-server-runtime": "^0.
|
|
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.
|
|
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",
|