rulesync 0.16.0 → 0.18.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/dist/index.js +122 -38
  2. package/dist/index.mjs +122 -38
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -368,14 +368,20 @@ var import_gray_matter = __toESM(require("gray-matter"));
368
368
  async function parseRulesFromDirectory(aiRulesDir) {
369
369
  const ruleFiles = await findFiles(aiRulesDir);
370
370
  const rules = [];
371
+ const errors = [];
371
372
  for (const filepath of ruleFiles) {
372
373
  try {
373
374
  const rule = await parseRuleFile(filepath);
374
375
  rules.push(rule);
375
376
  } catch (error) {
376
- console.warn(`Failed to parse rule file ${filepath}:`, error);
377
+ const errorMessage = error instanceof Error ? error.message : String(error);
378
+ errors.push(`Failed to parse rule file ${filepath}: ${errorMessage}`);
377
379
  }
378
380
  }
381
+ if (errors.length > 0) {
382
+ throw new Error(`Validation errors found:
383
+ ${errors.join("\n")}`);
384
+ }
379
385
  return rules;
380
386
  }
381
387
  async function parseRuleFile(filepath) {
@@ -393,14 +399,36 @@ async function parseRuleFile(filepath) {
393
399
  }
394
400
  function validateFrontmatter(data, filepath) {
395
401
  if (!data || typeof data !== "object") {
396
- throw new Error(`Invalid frontmatter in ${filepath}: must be an object`);
402
+ if (!data) {
403
+ throw new Error(
404
+ `Missing frontmatter in ${filepath}: file must contain YAML frontmatter with required fields (root, targets, description, globs)`
405
+ );
406
+ }
407
+ throw new Error(`Invalid frontmatter in ${filepath}: frontmatter must be a valid YAML object`);
397
408
  }
398
409
  const obj = data;
410
+ if (Object.keys(obj).length === 0) {
411
+ throw new Error(
412
+ `Missing frontmatter in ${filepath}: file must contain YAML frontmatter with required fields (root, targets, description, globs)`
413
+ );
414
+ }
415
+ if (obj.root === void 0) {
416
+ throw new Error(`Missing required field "root" in ${filepath}: must be true or false`);
417
+ }
399
418
  if (typeof obj.root !== "boolean") {
400
- throw new Error(`Invalid root in ${filepath}: must be a boolean`);
419
+ throw new Error(
420
+ `Invalid "root" field in ${filepath}: must be a boolean (true or false), got ${typeof obj.root}`
421
+ );
422
+ }
423
+ if (obj.targets === void 0) {
424
+ throw new Error(
425
+ `Missing required field "targets" in ${filepath}: must be an array like ["*"] or ["copilot", "cursor"]`
426
+ );
401
427
  }
402
428
  if (!Array.isArray(obj.targets)) {
403
- throw new Error(`Invalid targets in ${filepath}: must be an array`);
429
+ throw new Error(
430
+ `Invalid "targets" field in ${filepath}: must be an array, got ${typeof obj.targets}`
431
+ );
404
432
  }
405
433
  const validTargets = ["copilot", "cursor", "cline", "claude", "roo", "*"];
406
434
  for (const target of obj.targets) {
@@ -410,15 +438,31 @@ function validateFrontmatter(data, filepath) {
410
438
  );
411
439
  }
412
440
  }
441
+ if (obj.description === void 0) {
442
+ throw new Error(
443
+ `Missing required field "description" in ${filepath}: must be a descriptive string`
444
+ );
445
+ }
413
446
  if (!obj.description || typeof obj.description !== "string") {
414
- throw new Error(`Invalid description in ${filepath}: must be a non-empty string`);
447
+ throw new Error(
448
+ `Invalid "description" field in ${filepath}: must be a non-empty string, got ${typeof obj.description}`
449
+ );
450
+ }
451
+ if (obj.globs === void 0) {
452
+ throw new Error(
453
+ `Missing required field "globs" in ${filepath}: must be an array of file patterns like ["**/*.ts"]`
454
+ );
415
455
  }
416
456
  if (!Array.isArray(obj.globs)) {
417
- throw new Error(`Invalid globs in ${filepath}: must be an array`);
457
+ throw new Error(
458
+ `Invalid "globs" field in ${filepath}: must be an array, got ${typeof obj.globs}`
459
+ );
418
460
  }
419
461
  for (const glob of obj.globs) {
420
462
  if (typeof glob !== "string") {
421
- throw new Error(`Invalid glob in ${filepath}: all globs must be strings`);
463
+ throw new Error(
464
+ `Invalid glob pattern in ${filepath}: all globs must be strings, got ${typeof glob}`
465
+ );
422
466
  }
423
467
  }
424
468
  }
@@ -622,15 +666,15 @@ async function initCommand() {
622
666
  async function createSampleFiles(aiRulesDir) {
623
667
  const sampleFiles = [
624
668
  {
625
- filename: "coding-rules.md",
669
+ filename: "overview.md",
626
670
  content: `---
627
671
  root: true
628
672
  targets: ["*"]
629
- description: "General coding standards and best practices"
673
+ description: "Project overview and general development guidelines"
630
674
  globs: ["**/*.ts", "**/*.js", "**/*.tsx", "**/*.jsx"]
631
675
  ---
632
676
 
633
- # Coding Rules
677
+ # Project Overview
634
678
 
635
679
  ## General Guidelines
636
680
 
@@ -646,54 +690,94 @@ globs: ["**/*.ts", "**/*.js", "**/*.tsx", "**/*.jsx"]
646
690
  - Use semicolons
647
691
  - Use double quotes for strings
648
692
  - Use trailing commas in multi-line objects and arrays
693
+
694
+ ## Architecture Principles
695
+
696
+ - Organize code by feature, not by file type
697
+ - Keep related files close together
698
+ - Use dependency injection for better testability
699
+ - Implement proper error handling
700
+ - Follow single responsibility principle
649
701
  `
650
702
  },
651
703
  {
652
- filename: "naming-conventions.md",
704
+ filename: "frontend.md",
653
705
  content: `---
654
706
  root: false
655
707
  targets: ["*"]
656
- description: "Naming conventions for variables, functions, and files"
657
- globs: ["**/*.ts", "**/*.js"]
708
+ description: "Frontend development rules and best practices"
709
+ globs: ["src/components/**/*.tsx", "src/pages/**/*.tsx", "**/*.css", "**/*.scss"]
658
710
  ---
659
711
 
660
- # Naming Conventions
712
+ # Frontend Development Rules
713
+
714
+ ## React Components
661
715
 
662
- ## Variables and Functions
663
- - Use camelCase for variables and functions
664
- - Use descriptive names that explain the purpose
665
- - Avoid abbreviations unless they are well-known
716
+ - Use functional components with hooks
717
+ - Follow PascalCase naming for components
718
+ - Use TypeScript interfaces for props
719
+ - Implement proper error boundaries
666
720
 
667
- ## Files and Directories
668
- - Use kebab-case for file names
669
- - Use PascalCase for component files
670
- - Use lowercase for directory names
721
+ ## Styling
671
722
 
672
- ## Constants
673
- - Use SCREAMING_SNAKE_CASE for constants
674
- - Group related constants in enums or const objects
723
+ - Use CSS modules or styled-components
724
+ - Follow BEM methodology for CSS classes
725
+ - Prefer flexbox and grid for layouts
726
+ - Use semantic HTML elements
727
+
728
+ ## State Management
729
+
730
+ - Use React hooks for local state
731
+ - Consider Redux or Zustand for global state
732
+ - Avoid prop drilling with context API
733
+ - Keep state as close to where it's used as possible
734
+
735
+ ## Performance
736
+
737
+ - Use React.memo for expensive components
738
+ - Implement lazy loading for routes
739
+ - Optimize images and assets
740
+ - Use proper key props in lists
675
741
  `
676
742
  },
677
743
  {
678
- filename: "architecture.md",
744
+ filename: "backend.md",
679
745
  content: `---
680
746
  root: false
681
- targets: ["copilot", "cursor"]
682
- description: "Architectural patterns and project structure guidelines"
683
- globs: ["src/**/*.ts"]
747
+ targets: ["*"]
748
+ description: "Backend development rules and API guidelines"
749
+ globs: ["src/api/**/*.ts", "src/services/**/*.ts", "src/models/**/*.ts"]
684
750
  ---
685
751
 
686
- # Architecture Guidelines
752
+ # Backend Development Rules
687
753
 
688
- ## Project Structure
689
- - Organize code by feature, not by file type
690
- - Keep related files close together
691
- - Use index files for clean imports
754
+ ## API Design
692
755
 
693
- ## Design Patterns
694
- - Use dependency injection for better testability
695
- - Implement proper error handling
696
- - Follow single responsibility principle
756
+ - Follow RESTful conventions
757
+ - Use consistent HTTP status codes
758
+ - Implement proper error handling with meaningful messages
759
+ - Use API versioning when necessary
760
+
761
+ ## Database
762
+
763
+ - Use proper indexing for performance
764
+ - Implement database migrations
765
+ - Follow naming conventions for tables and columns
766
+ - Use transactions for data consistency
767
+
768
+ ## Security
769
+
770
+ - Validate all input data
771
+ - Use proper authentication and authorization
772
+ - Implement rate limiting
773
+ - Sanitize database queries to prevent SQL injection
774
+
775
+ ## Code Organization
776
+
777
+ - Use service layer pattern
778
+ - Implement proper logging
779
+ - Use environment variables for configuration
780
+ - Write comprehensive tests for business logic
697
781
  `
698
782
  }
699
783
  ];
package/dist/index.mjs CHANGED
@@ -345,14 +345,20 @@ import matter from "gray-matter";
345
345
  async function parseRulesFromDirectory(aiRulesDir) {
346
346
  const ruleFiles = await findFiles(aiRulesDir);
347
347
  const rules = [];
348
+ const errors = [];
348
349
  for (const filepath of ruleFiles) {
349
350
  try {
350
351
  const rule = await parseRuleFile(filepath);
351
352
  rules.push(rule);
352
353
  } catch (error) {
353
- console.warn(`Failed to parse rule file ${filepath}:`, error);
354
+ const errorMessage = error instanceof Error ? error.message : String(error);
355
+ errors.push(`Failed to parse rule file ${filepath}: ${errorMessage}`);
354
356
  }
355
357
  }
358
+ if (errors.length > 0) {
359
+ throw new Error(`Validation errors found:
360
+ ${errors.join("\n")}`);
361
+ }
356
362
  return rules;
357
363
  }
358
364
  async function parseRuleFile(filepath) {
@@ -370,14 +376,36 @@ async function parseRuleFile(filepath) {
370
376
  }
371
377
  function validateFrontmatter(data, filepath) {
372
378
  if (!data || typeof data !== "object") {
373
- throw new Error(`Invalid frontmatter in ${filepath}: must be an object`);
379
+ if (!data) {
380
+ throw new Error(
381
+ `Missing frontmatter in ${filepath}: file must contain YAML frontmatter with required fields (root, targets, description, globs)`
382
+ );
383
+ }
384
+ throw new Error(`Invalid frontmatter in ${filepath}: frontmatter must be a valid YAML object`);
374
385
  }
375
386
  const obj = data;
387
+ if (Object.keys(obj).length === 0) {
388
+ throw new Error(
389
+ `Missing frontmatter in ${filepath}: file must contain YAML frontmatter with required fields (root, targets, description, globs)`
390
+ );
391
+ }
392
+ if (obj.root === void 0) {
393
+ throw new Error(`Missing required field "root" in ${filepath}: must be true or false`);
394
+ }
376
395
  if (typeof obj.root !== "boolean") {
377
- throw new Error(`Invalid root in ${filepath}: must be a boolean`);
396
+ throw new Error(
397
+ `Invalid "root" field in ${filepath}: must be a boolean (true or false), got ${typeof obj.root}`
398
+ );
399
+ }
400
+ if (obj.targets === void 0) {
401
+ throw new Error(
402
+ `Missing required field "targets" in ${filepath}: must be an array like ["*"] or ["copilot", "cursor"]`
403
+ );
378
404
  }
379
405
  if (!Array.isArray(obj.targets)) {
380
- throw new Error(`Invalid targets in ${filepath}: must be an array`);
406
+ throw new Error(
407
+ `Invalid "targets" field in ${filepath}: must be an array, got ${typeof obj.targets}`
408
+ );
381
409
  }
382
410
  const validTargets = ["copilot", "cursor", "cline", "claude", "roo", "*"];
383
411
  for (const target of obj.targets) {
@@ -387,15 +415,31 @@ function validateFrontmatter(data, filepath) {
387
415
  );
388
416
  }
389
417
  }
418
+ if (obj.description === void 0) {
419
+ throw new Error(
420
+ `Missing required field "description" in ${filepath}: must be a descriptive string`
421
+ );
422
+ }
390
423
  if (!obj.description || typeof obj.description !== "string") {
391
- throw new Error(`Invalid description in ${filepath}: must be a non-empty string`);
424
+ throw new Error(
425
+ `Invalid "description" field in ${filepath}: must be a non-empty string, got ${typeof obj.description}`
426
+ );
427
+ }
428
+ if (obj.globs === void 0) {
429
+ throw new Error(
430
+ `Missing required field "globs" in ${filepath}: must be an array of file patterns like ["**/*.ts"]`
431
+ );
392
432
  }
393
433
  if (!Array.isArray(obj.globs)) {
394
- throw new Error(`Invalid globs in ${filepath}: must be an array`);
434
+ throw new Error(
435
+ `Invalid "globs" field in ${filepath}: must be an array, got ${typeof obj.globs}`
436
+ );
395
437
  }
396
438
  for (const glob of obj.globs) {
397
439
  if (typeof glob !== "string") {
398
- throw new Error(`Invalid glob in ${filepath}: all globs must be strings`);
440
+ throw new Error(
441
+ `Invalid glob pattern in ${filepath}: all globs must be strings, got ${typeof glob}`
442
+ );
399
443
  }
400
444
  }
401
445
  }
@@ -599,15 +643,15 @@ async function initCommand() {
599
643
  async function createSampleFiles(aiRulesDir) {
600
644
  const sampleFiles = [
601
645
  {
602
- filename: "coding-rules.md",
646
+ filename: "overview.md",
603
647
  content: `---
604
648
  root: true
605
649
  targets: ["*"]
606
- description: "General coding standards and best practices"
650
+ description: "Project overview and general development guidelines"
607
651
  globs: ["**/*.ts", "**/*.js", "**/*.tsx", "**/*.jsx"]
608
652
  ---
609
653
 
610
- # Coding Rules
654
+ # Project Overview
611
655
 
612
656
  ## General Guidelines
613
657
 
@@ -623,54 +667,94 @@ globs: ["**/*.ts", "**/*.js", "**/*.tsx", "**/*.jsx"]
623
667
  - Use semicolons
624
668
  - Use double quotes for strings
625
669
  - Use trailing commas in multi-line objects and arrays
670
+
671
+ ## Architecture Principles
672
+
673
+ - Organize code by feature, not by file type
674
+ - Keep related files close together
675
+ - Use dependency injection for better testability
676
+ - Implement proper error handling
677
+ - Follow single responsibility principle
626
678
  `
627
679
  },
628
680
  {
629
- filename: "naming-conventions.md",
681
+ filename: "frontend.md",
630
682
  content: `---
631
683
  root: false
632
684
  targets: ["*"]
633
- description: "Naming conventions for variables, functions, and files"
634
- globs: ["**/*.ts", "**/*.js"]
685
+ description: "Frontend development rules and best practices"
686
+ globs: ["src/components/**/*.tsx", "src/pages/**/*.tsx", "**/*.css", "**/*.scss"]
635
687
  ---
636
688
 
637
- # Naming Conventions
689
+ # Frontend Development Rules
690
+
691
+ ## React Components
638
692
 
639
- ## Variables and Functions
640
- - Use camelCase for variables and functions
641
- - Use descriptive names that explain the purpose
642
- - Avoid abbreviations unless they are well-known
693
+ - Use functional components with hooks
694
+ - Follow PascalCase naming for components
695
+ - Use TypeScript interfaces for props
696
+ - Implement proper error boundaries
643
697
 
644
- ## Files and Directories
645
- - Use kebab-case for file names
646
- - Use PascalCase for component files
647
- - Use lowercase for directory names
698
+ ## Styling
648
699
 
649
- ## Constants
650
- - Use SCREAMING_SNAKE_CASE for constants
651
- - Group related constants in enums or const objects
700
+ - Use CSS modules or styled-components
701
+ - Follow BEM methodology for CSS classes
702
+ - Prefer flexbox and grid for layouts
703
+ - Use semantic HTML elements
704
+
705
+ ## State Management
706
+
707
+ - Use React hooks for local state
708
+ - Consider Redux or Zustand for global state
709
+ - Avoid prop drilling with context API
710
+ - Keep state as close to where it's used as possible
711
+
712
+ ## Performance
713
+
714
+ - Use React.memo for expensive components
715
+ - Implement lazy loading for routes
716
+ - Optimize images and assets
717
+ - Use proper key props in lists
652
718
  `
653
719
  },
654
720
  {
655
- filename: "architecture.md",
721
+ filename: "backend.md",
656
722
  content: `---
657
723
  root: false
658
- targets: ["copilot", "cursor"]
659
- description: "Architectural patterns and project structure guidelines"
660
- globs: ["src/**/*.ts"]
724
+ targets: ["*"]
725
+ description: "Backend development rules and API guidelines"
726
+ globs: ["src/api/**/*.ts", "src/services/**/*.ts", "src/models/**/*.ts"]
661
727
  ---
662
728
 
663
- # Architecture Guidelines
729
+ # Backend Development Rules
664
730
 
665
- ## Project Structure
666
- - Organize code by feature, not by file type
667
- - Keep related files close together
668
- - Use index files for clean imports
731
+ ## API Design
669
732
 
670
- ## Design Patterns
671
- - Use dependency injection for better testability
672
- - Implement proper error handling
673
- - Follow single responsibility principle
733
+ - Follow RESTful conventions
734
+ - Use consistent HTTP status codes
735
+ - Implement proper error handling with meaningful messages
736
+ - Use API versioning when necessary
737
+
738
+ ## Database
739
+
740
+ - Use proper indexing for performance
741
+ - Implement database migrations
742
+ - Follow naming conventions for tables and columns
743
+ - Use transactions for data consistency
744
+
745
+ ## Security
746
+
747
+ - Validate all input data
748
+ - Use proper authentication and authorization
749
+ - Implement rate limiting
750
+ - Sanitize database queries to prevent SQL injection
751
+
752
+ ## Code Organization
753
+
754
+ - Use service layer pattern
755
+ - Implement proper logging
756
+ - Use environment variables for configuration
757
+ - Write comprehensive tests for business logic
674
758
  `
675
759
  }
676
760
  ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rulesync",
3
- "version": "0.16.0",
3
+ "version": "0.18.0",
4
4
  "description": "Unified AI rules management CLI tool that generates configuration files for various AI development tools",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",