@jay-framework/jay-stack-cli 0.10.0 → 0.11.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 (3) hide show
  1. package/README.md +76 -10
  2. package/dist/index.js +166 -3
  3. package/package.json +8 -5
package/README.md CHANGED
@@ -14,16 +14,68 @@ npm install @jay-framework/stack-cli
14
14
 
15
15
  ## Usage
16
16
 
17
- ### Basic Usage
17
+ ### Commands
18
18
 
19
- Simply run the CLI from your project root:
19
+ #### `jay-stack dev [path]`
20
+
21
+ Start the development server:
20
22
 
21
23
  ```bash
22
- @jay-framework/@jay-framework/jay-cli
24
+ jay-stack dev # Start dev server in current directory
25
+ jay-stack dev ./my-project # Start dev server in specified directory
23
26
  ```
24
27
 
25
28
  This will start both the development server and editor server with default configuration.
26
29
 
30
+ #### `jay-stack validate [path]`
31
+
32
+ Validate all `.jay-html` and `.jay-contract` files in the project without creating output files:
33
+
34
+ ```bash
35
+ jay-stack validate # Validate files in pagesBase from config
36
+ jay-stack validate ./src/pages # Validate files in specified directory
37
+ jay-stack validate --verbose # Show per-file validation status
38
+ jay-stack validate --json # Output results as JSON (for CI/tooling)
39
+ ```
40
+
41
+ This command is useful for:
42
+
43
+ - **CI pipelines**: Returns exit code 1 on validation errors
44
+ - **Development workflow**: Quick syntax checking without running the dev server
45
+ - **Vite integration**: Validate generated `.jay-html` files
46
+
47
+ Example output:
48
+
49
+ ```
50
+ ✅ Jay Stack validation successful!
51
+
52
+ Scanned 12 .jay-html files, 5 .jay-contract files
53
+ No errors found.
54
+ ```
55
+
56
+ Or with errors:
57
+
58
+ ```
59
+ ❌ Jay Stack validation failed
60
+
61
+ Errors:
62
+ ❌ src/pages/product/page.jay-html
63
+ jay file should have exactly one jay-data script, found 2
64
+
65
+ 1 error(s) found, 11 file(s) valid.
66
+ ```
67
+
68
+ #### `jay-stack validate-plugin [path]`
69
+
70
+ Validate a Jay Stack plugin package:
71
+
72
+ ```bash
73
+ jay-stack validate-plugin # Validate plugin in current directory
74
+ jay-stack validate-plugin ./my-plugin # Validate plugin in specified directory
75
+ jay-stack validate-plugin --verbose # Show detailed validation output
76
+ jay-stack validate-plugin --strict # Treat warnings as errors (for CI)
77
+ ```
78
+
27
79
  ### Configuration
28
80
 
29
81
  The CLI uses a `.jay` configuration file (YAML format) to customize port ranges for both servers. Create a `.jay` file in your project root:
@@ -143,15 +195,29 @@ The CLI is built using:
143
195
  - **get-port** - Automatic port discovery
144
196
  - **Vite** - Build tool integration
145
197
 
146
- ## Future Enhancements
198
+ ## CLI Reference
199
+
200
+ | Command | Description |
201
+ | ---------------------------------- | ---------------------------------------- |
202
+ | `jay-stack dev [path]` | Start the development server |
203
+ | `jay-stack validate [path]` | Validate jay-html and jay-contract files |
204
+ | `jay-stack validate-plugin [path]` | Validate a plugin package |
205
+
206
+ ### Validate Command Options
207
+
208
+ | Option | Description |
209
+ | --------------- | ------------------------------- |
210
+ | `-v, --verbose` | Show per-file validation status |
211
+ | `--json` | Output results as JSON |
147
212
 
148
- **Note**: The CLI currently does not accept command-line parameters. This will change in future versions to support:
213
+ ### Validate-Plugin Command Options
149
214
 
150
- - Custom pages directory path
151
- - Custom TypeScript configuration file
152
- - Custom output directory
153
- - Additional server configuration options
154
- - Development vs production modes
215
+ | Option | Description |
216
+ | ------------------ | -------------------------------------- |
217
+ | `-v, --verbose` | Show detailed validation output |
218
+ | `--strict` | Treat warnings as errors (for CI) |
219
+ | `--local` | Validate local plugins in src/plugins/ |
220
+ | `--generate-types` | Generate .d.ts files for contracts |
155
221
 
156
222
  ## Related Packages
157
223
 
package/dist/index.js CHANGED
@@ -4,14 +4,15 @@ import { mkDevServer } from "@jay-framework/dev-server";
4
4
  import { createEditorServer } from "@jay-framework/editor-server";
5
5
  import getPort from "get-port";
6
6
  import path from "path";
7
- import fs from "fs";
7
+ import fs, { promises } from "fs";
8
8
  import YAML from "yaml";
9
9
  import { parse } from "node-html-parser";
10
10
  import { createRequire } from "module";
11
- import { parseJayFile, JAY_IMPORT_RESOLVER, generateElementDefinitionFile, parseContract, ContractTagType } from "@jay-framework/compiler-jay-html";
12
- import { JAY_CONTRACT_EXTENSION, JAY_EXTENSION, JayAtomicType, JayEnumType, loadPluginManifest } from "@jay-framework/compiler-shared";
11
+ import { parseJayFile, JAY_IMPORT_RESOLVER, generateElementDefinitionFile, parseContract, ContractTagType, generateElementFile } from "@jay-framework/compiler-jay-html";
12
+ import { JAY_CONTRACT_EXTENSION, JAY_EXTENSION, JayAtomicType, JayEnumType, loadPluginManifest, RuntimeMode, GenerateTarget } from "@jay-framework/compiler-shared";
13
13
  import { Command } from "commander";
14
14
  import chalk from "chalk";
15
+ import { glob } from "glob";
15
16
  const DEFAULT_CONFIG = {
16
17
  devServer: {
17
18
  portRange: [3e3, 3100],
@@ -1459,6 +1460,148 @@ async function validateDynamicContracts(context, result) {
1459
1460
  }
1460
1461
  }
1461
1462
  }
1463
+ async function findJayFiles(dir) {
1464
+ return await glob(`${dir}/**/*${JAY_EXTENSION}`);
1465
+ }
1466
+ async function findContractFiles(dir) {
1467
+ return await glob(`${dir}/**/*${JAY_CONTRACT_EXTENSION}`);
1468
+ }
1469
+ async function validateJayFiles(options = {}) {
1470
+ const config = loadConfig();
1471
+ const resolvedConfig = getConfigWithDefaults(config);
1472
+ const projectRoot = process.cwd();
1473
+ const scanDir = options.path ? path.resolve(options.path) : path.resolve(resolvedConfig.devServer.pagesBase);
1474
+ const errors = [];
1475
+ const warnings = [];
1476
+ const jayHtmlFiles = await findJayFiles(scanDir);
1477
+ const contractFiles = await findContractFiles(scanDir);
1478
+ if (options.verbose) {
1479
+ console.log(chalk.gray(`Scanning directory: ${scanDir}`));
1480
+ console.log(chalk.gray(`Found ${jayHtmlFiles.length} .jay-html files`));
1481
+ console.log(chalk.gray(`Found ${contractFiles.length} .jay-contract files
1482
+ `));
1483
+ }
1484
+ for (const contractFile of contractFiles) {
1485
+ const relativePath = path.relative(projectRoot, contractFile);
1486
+ try {
1487
+ const content = await promises.readFile(contractFile, "utf-8");
1488
+ const result = parseContract(content, path.basename(contractFile));
1489
+ if (result.validations.length > 0) {
1490
+ for (const validation of result.validations) {
1491
+ errors.push({
1492
+ file: relativePath,
1493
+ message: validation,
1494
+ stage: "parse"
1495
+ });
1496
+ }
1497
+ if (options.verbose) {
1498
+ console.log(chalk.red(`❌ ${relativePath}`));
1499
+ }
1500
+ } else if (options.verbose) {
1501
+ console.log(chalk.green(`✓ ${relativePath}`));
1502
+ }
1503
+ } catch (error) {
1504
+ errors.push({
1505
+ file: relativePath,
1506
+ message: error.message,
1507
+ stage: "parse"
1508
+ });
1509
+ if (options.verbose) {
1510
+ console.log(chalk.red(`❌ ${relativePath}`));
1511
+ }
1512
+ }
1513
+ }
1514
+ for (const jayFile of jayHtmlFiles) {
1515
+ const relativePath = path.relative(projectRoot, jayFile);
1516
+ const filename = path.basename(jayFile.replace(JAY_EXTENSION, ""));
1517
+ const dirname = path.dirname(jayFile);
1518
+ try {
1519
+ const content = await promises.readFile(jayFile, "utf-8");
1520
+ const parsedFile = await parseJayFile(
1521
+ content,
1522
+ filename,
1523
+ dirname,
1524
+ {},
1525
+ JAY_IMPORT_RESOLVER,
1526
+ projectRoot
1527
+ );
1528
+ if (parsedFile.validations.length > 0) {
1529
+ for (const validation of parsedFile.validations) {
1530
+ errors.push({
1531
+ file: relativePath,
1532
+ message: validation,
1533
+ stage: "parse"
1534
+ });
1535
+ }
1536
+ if (options.verbose) {
1537
+ console.log(chalk.red(`❌ ${relativePath}`));
1538
+ }
1539
+ continue;
1540
+ }
1541
+ const generatedFile = generateElementFile(
1542
+ parsedFile.val,
1543
+ RuntimeMode.MainTrusted,
1544
+ GenerateTarget.jay
1545
+ );
1546
+ if (generatedFile.validations.length > 0) {
1547
+ for (const validation of generatedFile.validations) {
1548
+ errors.push({
1549
+ file: relativePath,
1550
+ message: validation,
1551
+ stage: "generate"
1552
+ });
1553
+ }
1554
+ if (options.verbose) {
1555
+ console.log(chalk.red(`❌ ${relativePath}`));
1556
+ }
1557
+ } else if (options.verbose) {
1558
+ console.log(chalk.green(`✓ ${relativePath}`));
1559
+ }
1560
+ } catch (error) {
1561
+ errors.push({
1562
+ file: relativePath,
1563
+ message: error.message,
1564
+ stage: "parse"
1565
+ });
1566
+ if (options.verbose) {
1567
+ console.log(chalk.red(`❌ ${relativePath}`));
1568
+ }
1569
+ }
1570
+ }
1571
+ return {
1572
+ valid: errors.length === 0,
1573
+ jayHtmlFilesScanned: jayHtmlFiles.length,
1574
+ contractFilesScanned: contractFiles.length,
1575
+ errors,
1576
+ warnings
1577
+ };
1578
+ }
1579
+ function printJayValidationResult(result, options) {
1580
+ if (options.json) {
1581
+ console.log(JSON.stringify(result, null, 2));
1582
+ return;
1583
+ }
1584
+ console.log("");
1585
+ if (result.valid) {
1586
+ console.log(chalk.green("✅ Jay Stack validation successful!\n"));
1587
+ console.log(
1588
+ `Scanned ${result.jayHtmlFilesScanned} .jay-html files, ${result.contractFilesScanned} .jay-contract files`
1589
+ );
1590
+ console.log("No errors found.");
1591
+ } else {
1592
+ console.log(chalk.red("❌ Jay Stack validation failed\n"));
1593
+ console.log("Errors:");
1594
+ for (const error of result.errors) {
1595
+ console.log(chalk.red(` ❌ ${error.file}`));
1596
+ console.log(chalk.gray(` ${error.message}`));
1597
+ console.log("");
1598
+ }
1599
+ const validFiles = result.jayHtmlFilesScanned + result.contractFilesScanned - result.errors.length;
1600
+ console.log(
1601
+ chalk.red(`${result.errors.length} error(s) found, ${validFiles} file(s) valid.`)
1602
+ );
1603
+ }
1604
+ }
1462
1605
  const program = new Command();
1463
1606
  program.name("jay-stack").description("Jay Stack CLI - Development server and plugin validation").version("0.9.0");
1464
1607
  program.command("dev [path]").description("Start the Jay Stack development server").action(async (path2, options) => {
@@ -1471,6 +1614,26 @@ program.command("dev [path]").description("Start the Jay Stack development serve
1471
1614
  process.exit(1);
1472
1615
  }
1473
1616
  });
1617
+ program.command("validate [path]").description("Validate all .jay-html and .jay-contract files in the project").option("-v, --verbose", "Show per-file validation status").option("--json", "Output results as JSON").action(async (scanPath, options) => {
1618
+ try {
1619
+ const result = await validateJayFiles({
1620
+ path: scanPath,
1621
+ verbose: options.verbose,
1622
+ json: options.json
1623
+ });
1624
+ printJayValidationResult(result, options);
1625
+ if (!result.valid) {
1626
+ process.exit(1);
1627
+ }
1628
+ } catch (error) {
1629
+ if (options.json) {
1630
+ console.log(JSON.stringify({ valid: false, error: error.message }, null, 2));
1631
+ } else {
1632
+ console.error(chalk.red("Validation error:"), error.message);
1633
+ }
1634
+ process.exit(1);
1635
+ }
1636
+ });
1474
1637
  program.command("validate-plugin [path]").description("Validate a Jay Stack plugin package").option("--local", "Validate local plugins in src/plugins/").option("-v, --verbose", "Show detailed validation output").option("--strict", "Treat warnings as errors (for CI)").option("--generate-types", "Generate .d.ts files for contracts").action(async (pluginPath, options) => {
1475
1638
  try {
1476
1639
  const result = await validatePlugin({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jay-framework/jay-stack-cli",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -23,16 +23,19 @@
23
23
  "test:watch": "vitest"
24
24
  },
25
25
  "dependencies": {
26
- "@jay-framework/dev-server": "^0.10.0",
27
- "@jay-framework/editor-server": "^0.10.0",
28
- "@jay-framework/plugin-validator": "^0.10.0",
26
+ "@jay-framework/compiler-jay-html": "^0.11.0",
27
+ "@jay-framework/compiler-shared": "^0.11.0",
28
+ "@jay-framework/dev-server": "^0.11.0",
29
+ "@jay-framework/editor-server": "^0.11.0",
30
+ "@jay-framework/plugin-validator": "^0.11.0",
29
31
  "chalk": "^4.1.2",
30
32
  "commander": "^14.0.0",
31
33
  "express": "^5.0.1",
34
+ "glob": "^10.3.10",
32
35
  "vite": "^5.0.11"
33
36
  },
34
37
  "devDependencies": {
35
- "@jay-framework/dev-environment": "^0.10.0",
38
+ "@jay-framework/dev-environment": "^0.11.0",
36
39
  "@types/express": "^5.0.2",
37
40
  "@types/node": "^22.15.21",
38
41
  "nodemon": "^3.0.3",