@sun-asterisk/sunlint 1.2.2 → 1.3.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 (64) hide show
  1. package/CHANGELOG.md +40 -1
  2. package/CONTRIBUTING.md +533 -70
  3. package/README.md +16 -2
  4. package/config/engines/engines-enhanced.json +86 -0
  5. package/config/engines/semantic-config.json +114 -0
  6. package/config/eslint-rule-mapping.json +50 -38
  7. package/config/rules/enhanced-rules-registry.json +2503 -0
  8. package/config/rules/rules-registry-generated.json +785 -837
  9. package/core/adapters/sunlint-rule-adapter.js +25 -30
  10. package/core/analysis-orchestrator.js +42 -2
  11. package/core/categories.js +52 -0
  12. package/core/category-constants.js +39 -0
  13. package/core/cli-action-handler.js +32 -5
  14. package/core/config-manager.js +111 -0
  15. package/core/config-merger.js +61 -0
  16. package/core/constants/categories.js +168 -0
  17. package/core/constants/defaults.js +165 -0
  18. package/core/constants/engines.js +185 -0
  19. package/core/constants/index.js +30 -0
  20. package/core/constants/rules.js +215 -0
  21. package/core/file-targeting-service.js +128 -7
  22. package/core/interfaces/rule-plugin.interface.js +207 -0
  23. package/core/plugin-manager.js +448 -0
  24. package/core/rule-selection-service.js +42 -15
  25. package/core/semantic-engine.js +560 -0
  26. package/core/semantic-rule-base.js +433 -0
  27. package/core/unified-rule-registry.js +484 -0
  28. package/docs/CONSTANTS-ARCHITECTURE.md +288 -0
  29. package/engines/core/base-engine.js +249 -0
  30. package/engines/engine-factory.js +275 -0
  31. package/engines/eslint-engine.js +171 -19
  32. package/engines/heuristic-engine.js +511 -78
  33. package/integrations/eslint/plugin/index.js +27 -27
  34. package/package.json +10 -6
  35. package/rules/common/C003_no_vague_abbreviations/analyzer.js +1 -1
  36. package/rules/common/C029_catch_block_logging/analyzer.js +17 -5
  37. package/rules/common/C047_no_duplicate_retry_logic/c047-semantic-rule.js +278 -0
  38. package/rules/common/C047_no_duplicate_retry_logic/symbol-analyzer-enhanced.js +968 -0
  39. package/rules/common/C047_no_duplicate_retry_logic/symbol-config.json +71 -0
  40. package/rules/index.js +7 -0
  41. package/scripts/category-manager.js +150 -0
  42. package/scripts/generate-rules-registry.js +88 -0
  43. package/scripts/migrate-rule-registry.js +157 -0
  44. package/scripts/validate-system.js +48 -0
  45. package/.sunlint.json +0 -35
  46. package/config/README.md +0 -88
  47. package/config/engines/eslint-rule-mapping.json +0 -74
  48. package/config/schemas/sunlint-schema.json +0 -0
  49. package/config/testing/test-s005-working.ts +0 -22
  50. package/core/multi-rule-runner.js +0 -0
  51. package/engines/tree-sitter-parser.js +0 -0
  52. package/engines/universal-ast-engine.js +0 -0
  53. package/rules/common/C029_catch_block_logging/analyzer-backup.js +0 -426
  54. package/rules/common/C029_catch_block_logging/analyzer-fixed.js +0 -130
  55. package/rules/common/C029_catch_block_logging/analyzer-multi-tech.js +0 -487
  56. package/rules/common/C029_catch_block_logging/analyzer-simple.js +0 -110
  57. package/rules/common/C029_catch_block_logging/ast-analyzer-backup.js +0 -441
  58. package/rules/common/C029_catch_block_logging/ast-analyzer-new.js +0 -127
  59. package/rules/common/C029_catch_block_logging/ast-analyzer.js +0 -133
  60. package/rules/common/C029_catch_block_logging/cfg-analyzer.js +0 -408
  61. package/rules/common/C029_catch_block_logging/dataflow-analyzer.js +0 -454
  62. package/rules/common/C029_catch_block_logging/multi-language-ast-engine.js +0 -700
  63. package/rules/common/C029_catch_block_logging/pattern-learning-analyzer.js +0 -568
  64. package/rules/common/C029_catch_block_logging/semantic-analyzer.js +0 -459
@@ -0,0 +1,215 @@
1
+ /**
2
+ * SunLint Rule Constants
3
+ * Constants related to rules, their metadata, and analysis
4
+ */
5
+
6
+ /**
7
+ * Rule severity levels (ordered by importance)
8
+ */
9
+ const RULE_SEVERITIES = {
10
+ ERROR: 'error',
11
+ WARNING: 'warning',
12
+ INFO: 'info',
13
+ HINT: 'hint'
14
+ };
15
+
16
+ /**
17
+ * Rule execution status
18
+ */
19
+ const RULE_STATUS = {
20
+ PENDING: 'pending',
21
+ RUNNING: 'running',
22
+ COMPLETED: 'completed',
23
+ FAILED: 'failed',
24
+ SKIPPED: 'skipped',
25
+ TIMEOUT: 'timeout'
26
+ };
27
+
28
+ /**
29
+ * Rule types based on analysis approach
30
+ */
31
+ const RULE_TYPES = {
32
+ HEURISTIC: 'heuristic', // Pattern-based analysis
33
+ AST: 'ast', // Abstract Syntax Tree analysis
34
+ SEMANTIC: 'semantic', // Semantic analysis
35
+ AI: 'ai', // AI-powered analysis
36
+ HYBRID: 'hybrid' // Combination of approaches
37
+ };
38
+
39
+ /**
40
+ * Rule scopes - what level the rule operates on
41
+ */
42
+ const RULE_SCOPES = {
43
+ FILE: 'file', // Single file analysis
44
+ PROJECT: 'project', // Project-wide analysis
45
+ MODULE: 'module', // Module/package analysis
46
+ FUNCTION: 'function', // Function-level analysis
47
+ CLASS: 'class', // Class-level analysis
48
+ EXPRESSION: 'expression' // Expression-level analysis
49
+ };
50
+
51
+ /**
52
+ * Rule language patterns for quick identification
53
+ */
54
+ const RULE_LANGUAGE_PATTERNS = {
55
+ COMMON: /^C\d{3}$/, // C001, C002, etc.
56
+ JAVASCRIPT: /^J\d{3}$/, // J001, J002, etc.
57
+ TYPESCRIPT: /^T\d{3}$/, // T001, T002, etc.
58
+ JAVA: /^JV\d{3}$/, // JV001, JV002, etc.
59
+ KOTLIN: /^K\d{3}$/, // K001, K002, etc.
60
+ DART: /^D\d{3}$/, // D001, D002, etc.
61
+ SWIFT: /^SW\d{3}$/, // SW001, SW002, etc.
62
+ PYTHON: /^PY\d{3}$/, // PY001, PY002, etc.
63
+ SECURITY: /^S\d{3}$/, // S001, S002, etc.
64
+ REACT: /^R\d{3}$/, // R001, R002, etc.
65
+ CUSTOM: /^CUSTOM_\w+$/ // Custom rules
66
+ };
67
+
68
+ /**
69
+ * Rule execution timeouts by type (in milliseconds)
70
+ */
71
+ const RULE_TIMEOUTS = {
72
+ [RULE_TYPES.HEURISTIC]: 5000, // 5 seconds
73
+ [RULE_TYPES.AST]: 10000, // 10 seconds
74
+ [RULE_TYPES.SEMANTIC]: 15000, // 15 seconds
75
+ [RULE_TYPES.AI]: 30000, // 30 seconds
76
+ [RULE_TYPES.HYBRID]: 20000 // 20 seconds
77
+ };
78
+
79
+ /**
80
+ * Rule confidence levels for AI/heuristic analysis
81
+ */
82
+ const CONFIDENCE_LEVELS = {
83
+ VERY_HIGH: 0.9,
84
+ HIGH: 0.8,
85
+ MEDIUM: 0.6,
86
+ LOW: 0.4,
87
+ VERY_LOW: 0.2
88
+ };
89
+
90
+ /**
91
+ * Default rule metadata template
92
+ */
93
+ const DEFAULT_RULE_METADATA = {
94
+ severity: RULE_SEVERITIES.WARNING,
95
+ type: RULE_TYPES.HEURISTIC,
96
+ scope: RULE_SCOPES.FILE,
97
+ category: 'quality',
98
+ languages: [],
99
+ description: '',
100
+ examples: {
101
+ good: [],
102
+ bad: []
103
+ },
104
+ tags: [],
105
+ fixable: false,
106
+ confidence: CONFIDENCE_LEVELS.HIGH
107
+ };
108
+
109
+ /**
110
+ * Rule performance metrics template
111
+ */
112
+ const RULE_PERFORMANCE_TEMPLATE = {
113
+ executionTime: 0,
114
+ filesAnalyzed: 0,
115
+ violationsFound: 0,
116
+ falsePositives: 0,
117
+ memoryUsage: 0,
118
+ cacheHits: 0
119
+ };
120
+
121
+ /**
122
+ * Get language from rule ID
123
+ * @param {string} ruleId - Rule identifier (e.g., "C001", "J005")
124
+ * @returns {string|null} Language name or null if not found
125
+ */
126
+ function getLanguageFromRuleId(ruleId) {
127
+ const patterns = {
128
+ javascript: RULE_LANGUAGE_PATTERNS.JAVASCRIPT,
129
+ typescript: RULE_LANGUAGE_PATTERNS.TYPESCRIPT,
130
+ java: RULE_LANGUAGE_PATTERNS.JAVA,
131
+ kotlin: RULE_LANGUAGE_PATTERNS.KOTLIN,
132
+ dart: RULE_LANGUAGE_PATTERNS.DART,
133
+ swift: RULE_LANGUAGE_PATTERNS.SWIFT,
134
+ python: RULE_LANGUAGE_PATTERNS.PYTHON,
135
+ react: RULE_LANGUAGE_PATTERNS.REACT
136
+ };
137
+
138
+ for (const [language, pattern] of Object.entries(patterns)) {
139
+ if (pattern.test(ruleId)) {
140
+ return language;
141
+ }
142
+ }
143
+
144
+ // Check for common rules
145
+ if (RULE_LANGUAGE_PATTERNS.COMMON.test(ruleId)) {
146
+ return 'common';
147
+ }
148
+
149
+ // Check for security rules
150
+ if (RULE_LANGUAGE_PATTERNS.SECURITY.test(ruleId)) {
151
+ return 'security';
152
+ }
153
+
154
+ return null;
155
+ }
156
+
157
+ /**
158
+ * Check if rule ID is valid format
159
+ * @param {string} ruleId - Rule identifier
160
+ * @returns {boolean} True if valid format
161
+ */
162
+ function isValidRuleId(ruleId) {
163
+ const allPatterns = Object.values(RULE_LANGUAGE_PATTERNS);
164
+ return allPatterns.some(pattern => pattern.test(ruleId));
165
+ }
166
+
167
+ /**
168
+ * Get rule timeout by type
169
+ * @param {string} ruleType - Rule type
170
+ * @returns {number} Timeout in milliseconds
171
+ */
172
+ function getRuleTimeout(ruleType) {
173
+ return RULE_TIMEOUTS[ruleType] || RULE_TIMEOUTS[RULE_TYPES.HEURISTIC];
174
+ }
175
+
176
+ /**
177
+ * Get default rule metadata with overrides
178
+ * @param {Object} overrides - Metadata overrides
179
+ * @returns {Object} Merged metadata
180
+ */
181
+ function getDefaultRuleMetadata(overrides = {}) {
182
+ return {
183
+ ...DEFAULT_RULE_METADATA,
184
+ ...overrides
185
+ };
186
+ }
187
+
188
+ /**
189
+ * Check if severity level is valid
190
+ * @param {string} severity - Severity level
191
+ * @returns {boolean} True if valid
192
+ */
193
+ function isValidSeverity(severity) {
194
+ return Object.values(RULE_SEVERITIES).includes(severity);
195
+ }
196
+
197
+ module.exports = {
198
+ // Rule constants
199
+ RULE_SEVERITIES,
200
+ RULE_STATUS,
201
+ RULE_TYPES,
202
+ RULE_SCOPES,
203
+ RULE_LANGUAGE_PATTERNS,
204
+ RULE_TIMEOUTS,
205
+ CONFIDENCE_LEVELS,
206
+ DEFAULT_RULE_METADATA,
207
+ RULE_PERFORMANCE_TEMPLATE,
208
+
209
+ // Utility functions
210
+ getLanguageFromRuleId,
211
+ isValidRuleId,
212
+ getRuleTimeout,
213
+ getDefaultRuleMetadata,
214
+ isValidSeverity
215
+ };
@@ -1,5 +1,6 @@
1
1
  const path = require('path');
2
2
  const fs = require('fs');
3
+ const chalk = require('chalk');
3
4
  const { minimatch } = require('minimatch');
4
5
 
5
6
  /**
@@ -15,24 +16,42 @@ class FileTargetingService {
15
16
 
16
17
  /**
17
18
  * Get target files based on enhanced configuration
18
- * Rule C012: Command method - performs file selection
19
+ * ENHANCED: Uses metadata for intelligent file targeting
19
20
  */
20
21
  async getTargetFiles(inputPaths, config, cliOptions = {}) {
21
22
  try {
22
- const allFiles = [];
23
+ const startTime = Date.now();
24
+ const metadata = config._metadata;
23
25
 
24
- // Collect all files from input paths
25
- for (const inputPath of inputPaths) {
26
- const files = await this.collectFiles(inputPath);
27
- allFiles.push(...files);
26
+ if (cliOptions.verbose) {
27
+ console.log(chalk.cyan(`📁 File Targeting: ${this.getTargetingMode(metadata)}`));
28
+ if (metadata?.shouldBypassProjectDiscovery) {
29
+ console.log(chalk.blue(`🎯 Optimized targeting for ${metadata.analysisScope}`));
30
+ }
31
+ }
32
+
33
+ let allFiles = [];
34
+
35
+ // Use enhanced targeting based on metadata
36
+ if (metadata?.shouldBypassProjectDiscovery) {
37
+ allFiles = await this.collectTargetedFiles(inputPaths, config, cliOptions);
38
+ } else {
39
+ allFiles = await this.collectProjectFiles(inputPaths, config, cliOptions);
28
40
  }
29
41
 
30
42
  // Apply filtering logic
31
43
  const targetFiles = this.applyFiltering(allFiles, config, cliOptions);
32
44
 
45
+ const duration = Date.now() - startTime;
46
+
47
+ if (cliOptions.verbose) {
48
+ console.log(chalk.green(`✅ File targeting completed in ${duration}ms (${targetFiles.length} files)`));
49
+ }
50
+
33
51
  return {
34
52
  files: targetFiles,
35
- stats: this.generateStats(targetFiles, config)
53
+ stats: this.generateStats(targetFiles, config),
54
+ timing: { duration, filesPerMs: targetFiles.length / Math.max(duration, 1) }
36
55
  };
37
56
  } catch (error) {
38
57
  console.error('❌ FileTargetingService error:', error);
@@ -40,6 +59,108 @@ class FileTargetingService {
40
59
  }
41
60
  }
42
61
 
62
+ /**
63
+ * Get targeting mode description
64
+ */
65
+ getTargetingMode(metadata) {
66
+ if (!metadata) return 'legacy';
67
+
68
+ if (metadata.shouldBypassProjectDiscovery) {
69
+ return metadata.analysisScope === 'file' ? 'single_file' : 'folder_targeted';
70
+ } else {
71
+ return 'project_wide';
72
+ }
73
+ }
74
+
75
+ /**
76
+ * Collect files with targeted approach (bypassing project discovery)
77
+ */
78
+ async collectTargetedFiles(inputPaths, config, cliOptions) {
79
+ const files = [];
80
+
81
+ for (const inputPath of inputPaths) {
82
+ const resolvedPath = path.resolve(inputPath);
83
+
84
+ if (!fs.existsSync(resolvedPath)) {
85
+ if (cliOptions.verbose) {
86
+ console.log(chalk.yellow(`⚠️ Path not found: ${inputPath}`));
87
+ }
88
+ continue;
89
+ }
90
+
91
+ const stat = fs.statSync(resolvedPath);
92
+
93
+ if (stat.isFile()) {
94
+ // Single file targeting
95
+ files.push(resolvedPath);
96
+ } else if (stat.isDirectory()) {
97
+ // Folder-only targeting (no recursive project scan)
98
+ const folderFiles = await this.collectFolderFiles(resolvedPath);
99
+ files.push(...folderFiles);
100
+ }
101
+ }
102
+
103
+ return files;
104
+ }
105
+
106
+ /**
107
+ * Collect files from specific folder (no project-wide scanning)
108
+ */
109
+ async collectFolderFiles(folderPath) {
110
+ const files = [];
111
+ const targetExtensions = ['.ts', '.tsx', '.js', '.jsx', '.dart', '.kt', '.kts'];
112
+
113
+ try {
114
+ const entries = fs.readdirSync(folderPath);
115
+
116
+ for (const entry of entries) {
117
+ const fullPath = path.join(folderPath, entry);
118
+ const stat = fs.statSync(fullPath);
119
+
120
+ if (stat.isFile()) {
121
+ const ext = path.extname(fullPath);
122
+ if (targetExtensions.includes(ext)) {
123
+ files.push(path.resolve(fullPath));
124
+ }
125
+ } else if (stat.isDirectory() && !this.shouldSkipDirectory(entry)) {
126
+ // Recursive collection within target folder only
127
+ const subFiles = await this.collectFolderFiles(fullPath);
128
+ files.push(...subFiles);
129
+ }
130
+ }
131
+ } catch (error) {
132
+ console.warn(`⚠️ Error reading folder ${folderPath}: ${error.message}`);
133
+ }
134
+
135
+ return files;
136
+ }
137
+
138
+ /**
139
+ * Collect files with project-wide approach (original logic)
140
+ */
141
+ async collectProjectFiles(inputPaths, config, cliOptions) {
142
+ const allFiles = [];
143
+
144
+ // Use original collection logic for project-wide analysis
145
+ for (const inputPath of inputPaths) {
146
+ const files = await this.collectFiles(inputPath);
147
+ allFiles.push(...files);
148
+ }
149
+
150
+ return allFiles;
151
+ }
152
+
153
+ /**
154
+ * Check if directory should be skipped
155
+ */
156
+ shouldSkipDirectory(dirName) {
157
+ const skipDirs = [
158
+ 'node_modules', '.git', 'dist', 'build', 'coverage',
159
+ '.next', '.nuxt', 'vendor', 'target', 'generated'
160
+ ];
161
+ return skipDirs.includes(dirName);
162
+ }
163
+
43
164
  /**
44
165
  * Apply comprehensive filtering logic
45
166
  * Priority: CLI > Config > Default
@@ -0,0 +1,207 @@
1
+ /**
2
+ * Rule Plugin Interface
3
+ * Defines the contract for all rule plugins in SunLint
4
+ * Following Rule C014: Dependency injection - Plugin interface
5
+ */
6
+
7
+ class RulePluginInterface {
8
+ constructor(ruleId, metadata = {}) {
9
+ if (this.constructor === RulePluginInterface) {
10
+ throw new Error('RulePluginInterface is abstract and cannot be instantiated');
11
+ }
12
+
13
+ this.ruleId = ruleId;
14
+ this.metadata = {
15
+ name: metadata.name || ruleId,
16
+ description: metadata.description || '',
17
+ category: metadata.category || 'custom',
18
+ severity: metadata.severity || 'warning',
19
+ languages: metadata.languages || ['javascript', 'typescript'],
20
+ version: metadata.version || '1.0.0',
21
+ author: metadata.author || '',
22
+ tags: metadata.tags || [],
23
+ ...metadata
24
+ };
25
+ }
26
+
27
+ /**
28
+ * Initialize the rule plugin
29
+ * @param {Object} config - Rule configuration
30
+ * @returns {Promise<void>}
31
+ */
32
+ async initialize(config = {}) {
33
+ throw new Error('initialize() must be implemented by rule plugin');
34
+ }
35
+
36
+ /**
37
+ * Analyze files for violations
38
+ * @param {string[]} files - Files to analyze
39
+ * @param {string} language - Programming language
40
+ * @param {Object} options - Analysis options
41
+ * @returns {Promise<Object[]>} Array of violations
42
+ */
43
+ async analyze(files, language, options = {}) {
44
+ throw new Error('analyze() must be implemented by rule plugin');
45
+ }
46
+
47
+ /**
48
+ * Get rule metadata
49
+ * @returns {Object} Rule metadata
50
+ */
51
+ getMetadata() {
52
+ return this.metadata;
53
+ }
54
+
55
+ /**
56
+ * Check if rule supports a language
57
+ * @param {string} language - Language to check
58
+ * @returns {boolean} True if supported
59
+ */
60
+ supportsLanguage(language) {
61
+ return this.metadata.languages.includes(language) ||
62
+ this.metadata.languages.includes('all');
63
+ }
64
+
65
+ /**
66
+ * Validate rule configuration
67
+ * @param {Object} config - Configuration to validate
68
+ * @returns {Object} Validation result
69
+ */
70
+ validateConfig(config) {
71
+ return {
72
+ isValid: true,
73
+ errors: [],
74
+ warnings: []
75
+ };
76
+ }
77
+
78
+ /**
79
+ * Get rule documentation
80
+ * @returns {Object} Documentation object
81
+ */
82
+ getDocumentation() {
83
+ return {
84
+ name: this.metadata.name,
85
+ description: this.metadata.description,
86
+ examples: [],
87
+ configuration: {},
88
+ links: []
89
+ };
90
+ }
91
+
92
+ /**
93
+ * Cleanup rule resources
94
+ * @returns {Promise<void>}
95
+ */
96
+ async cleanup() {
97
+ // Default implementation - can be overridden
98
+ }
99
+ }
100
+
101
+ /**
102
+ * Semantic Rule Interface
103
+ * For rules that use symbol table and semantic analysis
104
+ */
105
+ class SemanticRuleInterface extends RulePluginInterface {
106
+ constructor(ruleId, metadata = {}) {
107
+ super(ruleId, { ...metadata, type: 'semantic' });
108
+ this.semanticEngine = null;
109
+ this.violations = [];
110
+ }
111
+
112
+ /**
113
+ * Initialize with semantic engine
114
+ * @param {Object} semanticEngine - Semantic analysis engine
115
+ */
116
+ initializeSemanticEngine(semanticEngine) {
117
+ this.semanticEngine = semanticEngine;
118
+ }
119
+
120
+ /**
121
+ * Analyze a single file using semantic analysis
122
+ * @param {string} filePath - File to analyze
123
+ * @param {Object} options - Analysis options
124
+ * @returns {Promise<void>}
125
+ */
126
+ async analyzeFile(filePath, options = {}) {
127
+ throw new Error('analyzeFile() must be implemented by semantic rule');
128
+ }
129
+
130
+ /**
131
+ * Get violations found during analysis
132
+ * @returns {Object[]} Array of violations
133
+ */
134
+ getViolations() {
135
+ return this.violations;
136
+ }
137
+
138
+ /**
139
+ * Clear violations for next analysis
140
+ */
141
+ clearViolations() {
142
+ this.violations = [];
143
+ }
144
+
145
+ /**
146
+ * Add a violation
147
+ * @param {Object} violation - Violation object
148
+ */
149
+ addViolation(violation) {
150
+ this.violations.push({
151
+ ruleId: this.ruleId,
152
+ severity: this.metadata.severity,
153
+ ...violation
154
+ });
155
+ }
156
+ }
157
+
158
+ /**
159
+ * Custom Rule Interface
160
+ * For user-defined custom rules
161
+ */
162
+ class CustomRuleInterface extends RulePluginInterface {
163
+ constructor(ruleId, metadata = {}) {
164
+ super(ruleId, { ...metadata, type: 'custom', source: 'user' });
165
+ this.configSchema = null;
166
+ }
167
+
168
+ /**
169
+ * Set configuration schema for validation
170
+ * @param {Object} schema - JSON schema for configuration
171
+ */
172
+ setConfigSchema(schema) {
173
+ this.configSchema = schema;
174
+ }
175
+
176
+ /**
177
+ * Validate configuration against schema
178
+ * @param {Object} config - Configuration to validate
179
+ * @returns {Object} Validation result
180
+ */
181
+ validateConfig(config) {
182
+ if (!this.configSchema) {
183
+ return super.validateConfig(config);
184
+ }
185
+
186
+ // TODO: Implement JSON schema validation
187
+ return {
188
+ isValid: true,
189
+ errors: [],
190
+ warnings: []
191
+ };
192
+ }
193
+
194
+ /**
195
+ * Register custom helper methods
196
+ * @param {Object} helpers - Helper methods
197
+ */
198
+ registerHelpers(helpers) {
199
+ this.helpers = helpers;
200
+ }
201
+ }
202
+
203
+ module.exports = {
204
+ RulePluginInterface,
205
+ SemanticRuleInterface,
206
+ CustomRuleInterface
207
+ };