@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.
- package/dist/index.js +108 -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,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:
|
|
4302
|
-
name:
|
|
4303
|
-
tags:
|
|
4304
|
-
props:
|
|
4305
|
-
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
|
-
|
|
4309
|
-
|
|
4310
|
-
|
|
4311
|
-
|
|
4312
|
-
|
|
4313
|
-
|
|
4314
|
-
|
|
4315
|
-
|
|
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
|
-
|
|
4508
|
-
|
|
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
|
-
|
|
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
|
-
|
|
4515
|
-
|
|
4516
|
-
|
|
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(`
|
|
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
|
-
|
|
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.
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
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(`
|
|
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(`
|
|
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
|
-
`
|
|
4600
|
+
` ${label}: ${contract.usedTags}/${contract.totalTags} tags used`
|
|
4552
4601
|
);
|
|
4553
4602
|
if (contract.unusedTags.length > 0) {
|
|
4554
|
-
logger.important(
|
|
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
|
-
`
|
|
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.
|
|
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.
|
|
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.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.
|
|
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",
|