@idealyst/tooling 1.2.24 → 1.2.26

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 (57) hide show
  1. package/dist/analyzer/index.cjs +727 -0
  2. package/dist/analyzer/index.cjs.map +1 -0
  3. package/dist/analyzer/index.d.cts +65 -0
  4. package/dist/analyzer/index.d.ts +65 -0
  5. package/dist/analyzer/index.js +687 -0
  6. package/dist/analyzer/index.js.map +1 -0
  7. package/dist/analyzers/index.cjs +1201 -0
  8. package/dist/analyzers/index.cjs.map +1 -0
  9. package/dist/analyzers/index.d.cts +205 -0
  10. package/dist/analyzers/index.d.ts +205 -0
  11. package/dist/analyzers/index.js +1155 -0
  12. package/dist/analyzers/index.js.map +1 -0
  13. package/dist/index.cjs +2143 -0
  14. package/dist/index.cjs.map +1 -0
  15. package/dist/index.d.cts +55 -0
  16. package/dist/index.d.ts +55 -0
  17. package/dist/index.js +2061 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/rules/index.cjs +522 -0
  20. package/dist/rules/index.cjs.map +1 -0
  21. package/dist/rules/index.d.cts +69 -0
  22. package/dist/rules/index.d.ts +69 -0
  23. package/dist/rules/index.js +481 -0
  24. package/dist/rules/index.js.map +1 -0
  25. package/dist/types-CrlxbLFJ.d.cts +121 -0
  26. package/dist/types-CrlxbLFJ.d.ts +121 -0
  27. package/dist/types-CvIlSIOV.d.cts +149 -0
  28. package/dist/types-CvIlSIOV.d.ts +149 -0
  29. package/dist/utils/index.cjs +709 -0
  30. package/dist/utils/index.cjs.map +1 -0
  31. package/dist/utils/index.d.cts +94 -0
  32. package/dist/utils/index.d.ts +94 -0
  33. package/dist/utils/index.js +662 -0
  34. package/dist/utils/index.js.map +1 -0
  35. package/dist/vite-plugin.cjs +800 -0
  36. package/dist/vite-plugin.cjs.map +1 -0
  37. package/dist/vite-plugin.d.cts +40 -0
  38. package/dist/vite-plugin.d.ts +40 -0
  39. package/dist/vite-plugin.js +764 -0
  40. package/dist/vite-plugin.js.map +1 -0
  41. package/package.json +26 -24
  42. package/src/analyzer/component-analyzer.ts +0 -554
  43. package/src/analyzer/index.ts +0 -16
  44. package/src/analyzer/theme-analyzer.ts +0 -473
  45. package/src/analyzer/types.ts +0 -159
  46. package/src/analyzers/componentLinter.ts +0 -397
  47. package/src/analyzers/index.ts +0 -2
  48. package/src/analyzers/platformImports.ts +0 -391
  49. package/src/index.ts +0 -156
  50. package/src/rules/index.ts +0 -2
  51. package/src/rules/reactDomPrimitives.ts +0 -217
  52. package/src/rules/reactNativePrimitives.ts +0 -362
  53. package/src/types.ts +0 -173
  54. package/src/utils/fileClassifier.ts +0 -135
  55. package/src/utils/importParser.ts +0 -235
  56. package/src/utils/index.ts +0 -2
  57. package/src/vite-plugin.ts +0 -199
@@ -1,391 +0,0 @@
1
- import {
2
- AnalyzerOptions,
3
- AnalysisResult,
4
- FileInput,
5
- ImportInfo,
6
- Severity,
7
- Violation,
8
- ViolationType,
9
- } from '../types';
10
- import { classifyFile } from '../utils/fileClassifier';
11
- import { parseImports } from '../utils/importParser';
12
- import {
13
- REACT_NATIVE_SOURCES,
14
- isReactNativePrimitive,
15
- } from '../rules/reactNativePrimitives';
16
- import {
17
- isReactDomPrimitive,
18
- } from '../rules/reactDomPrimitives';
19
-
20
- /**
21
- * Default analyzer options
22
- */
23
- const DEFAULT_OPTIONS: Required<AnalyzerOptions> = {
24
- severity: 'error',
25
- additionalNativePrimitives: [],
26
- additionalDomPrimitives: [],
27
- ignoredPrimitives: [],
28
- ignoredPatterns: [],
29
- additionalNativeSources: [],
30
- additionalDomSources: [],
31
- };
32
-
33
- /**
34
- * Check if a file path matches any of the ignored patterns
35
- */
36
- function matchesIgnoredPattern(
37
- filePath: string,
38
- patterns: string[]
39
- ): boolean {
40
- if (patterns.length === 0) return false;
41
-
42
- for (const pattern of patterns) {
43
- // Simple glob matching - convert glob to regex
44
- const regexPattern = pattern
45
- .replace(/\*\*/g, '{{GLOBSTAR}}')
46
- .replace(/\*/g, '[^/]*')
47
- .replace(/{{GLOBSTAR}}/g, '.*')
48
- .replace(/\?/g, '.');
49
-
50
- const regex = new RegExp(regexPattern);
51
- if (regex.test(filePath)) {
52
- return true;
53
- }
54
- }
55
-
56
- return false;
57
- }
58
-
59
- /**
60
- * Creates a violation object
61
- */
62
- function createViolation(
63
- type: ViolationType,
64
- primitive: string,
65
- source: string,
66
- filePath: string,
67
- line: number,
68
- column: number,
69
- severity: Severity
70
- ): Violation {
71
- const messages: Record<ViolationType, string> = {
72
- 'native-in-shared': `React Native primitive '${primitive}' from '${source}' should not be used in shared files. Use a .native.tsx file instead.`,
73
- 'dom-in-shared': `React DOM primitive '${primitive}' from '${source}' should not be used in shared files. Use a .web.tsx file instead.`,
74
- 'native-in-web': `React Native primitive '${primitive}' from '${source}' should not be used in web-specific files.`,
75
- 'dom-in-native': `React DOM primitive '${primitive}' from '${source}' should not be used in native-specific files.`,
76
- };
77
-
78
- return {
79
- type,
80
- primitive,
81
- source,
82
- filePath,
83
- line,
84
- column,
85
- message: messages[type],
86
- severity,
87
- };
88
- }
89
-
90
- /**
91
- * Check if an import should be flagged as a React Native primitive
92
- */
93
- function isNativePrimitive(
94
- importInfo: ImportInfo,
95
- additionalPrimitives: string[]
96
- ): boolean {
97
- const name = importInfo.originalName ?? importInfo.name;
98
-
99
- // Check built-in primitives
100
- if (isReactNativePrimitive(name)) return true;
101
-
102
- // Check additional primitives
103
- if (additionalPrimitives.includes(name)) return true;
104
-
105
- // Check if the source is a known React Native source
106
- const nativeSources: Set<string> = new Set([...REACT_NATIVE_SOURCES]);
107
- if (nativeSources.has(importInfo.source)) {
108
- // Any import from react-native that's a component (starts with uppercase)
109
- if (/^[A-Z]/.test(name)) return true;
110
- }
111
-
112
- return false;
113
- }
114
-
115
- /**
116
- * Check if an import should be flagged as a React DOM primitive
117
- */
118
- function isDomPrimitive(
119
- importInfo: ImportInfo,
120
- additionalPrimitives: string[]
121
- ): boolean {
122
- const name = importInfo.originalName ?? importInfo.name;
123
-
124
- // Check built-in primitives
125
- if (isReactDomPrimitive(name)) return true;
126
-
127
- // Check additional primitives
128
- if (additionalPrimitives.includes(name)) return true;
129
-
130
- return false;
131
- }
132
-
133
- /**
134
- * Analyze a single file for platform import violations
135
- *
136
- * @param filePath - Path to the file being analyzed
137
- * @param sourceCode - The source code content
138
- * @param options - Analyzer options
139
- * @returns Analysis result with violations
140
- *
141
- * @example
142
- * ```typescript
143
- * const result = analyzePlatformImports(
144
- * 'src/components/Button.tsx',
145
- * sourceCode,
146
- * { severity: 'error' }
147
- * );
148
- *
149
- * if (result.violations.length > 0) {
150
- * for (const v of result.violations) {
151
- * console.error(`${v.filePath}:${v.line}:${v.column} - ${v.message}`);
152
- * }
153
- * }
154
- * ```
155
- */
156
- export function analyzePlatformImports(
157
- filePath: string,
158
- sourceCode: string,
159
- options?: AnalyzerOptions
160
- ): AnalysisResult {
161
- const opts = { ...DEFAULT_OPTIONS, ...options };
162
- const fileType = classifyFile(filePath);
163
- const violations: Violation[] = [];
164
-
165
- // Skip ignored files
166
- if (matchesIgnoredPattern(filePath, opts.ignoredPatterns)) {
167
- return {
168
- filePath,
169
- fileType,
170
- violations: [],
171
- imports: [],
172
- passed: true,
173
- };
174
- }
175
-
176
- // Skip non-component files
177
- if (fileType === 'other' || fileType === 'styles' || fileType === 'types') {
178
- return {
179
- filePath,
180
- fileType,
181
- violations: [],
182
- imports: [],
183
- passed: true,
184
- };
185
- }
186
-
187
- // Parse imports
188
- const imports = parseImports(sourceCode, filePath, {
189
- additionalNativeSources: opts.additionalNativeSources,
190
- additionalDomSources: opts.additionalDomSources,
191
- });
192
-
193
- // Build ignored primitives set
194
- const ignoredPrimitives = new Set(opts.ignoredPrimitives);
195
-
196
- // Analyze each import
197
- for (const imp of imports) {
198
- // Skip type-only imports
199
- if (imp.isTypeOnly) continue;
200
-
201
- // Skip ignored primitives
202
- const primitiveName = imp.originalName ?? imp.name;
203
- if (ignoredPrimitives.has(primitiveName)) continue;
204
-
205
- // Check for violations based on file type
206
- switch (fileType) {
207
- case 'shared':
208
- // Shared files should not use platform-specific imports
209
- if (isNativePrimitive(imp, opts.additionalNativePrimitives)) {
210
- violations.push(
211
- createViolation(
212
- 'native-in-shared',
213
- primitiveName,
214
- imp.source,
215
- filePath,
216
- imp.line,
217
- imp.column,
218
- opts.severity
219
- )
220
- );
221
- }
222
- if (isDomPrimitive(imp, opts.additionalDomPrimitives)) {
223
- violations.push(
224
- createViolation(
225
- 'dom-in-shared',
226
- primitiveName,
227
- imp.source,
228
- filePath,
229
- imp.line,
230
- imp.column,
231
- opts.severity
232
- )
233
- );
234
- }
235
- break;
236
-
237
- case 'web':
238
- // Web files should not use React Native imports
239
- if (isNativePrimitive(imp, opts.additionalNativePrimitives)) {
240
- violations.push(
241
- createViolation(
242
- 'native-in-web',
243
- primitiveName,
244
- imp.source,
245
- filePath,
246
- imp.line,
247
- imp.column,
248
- opts.severity
249
- )
250
- );
251
- }
252
- break;
253
-
254
- case 'native':
255
- // Native files should not use React DOM imports
256
- if (isDomPrimitive(imp, opts.additionalDomPrimitives)) {
257
- violations.push(
258
- createViolation(
259
- 'dom-in-native',
260
- primitiveName,
261
- imp.source,
262
- filePath,
263
- imp.line,
264
- imp.column,
265
- opts.severity
266
- )
267
- );
268
- }
269
- break;
270
- }
271
- }
272
-
273
- return {
274
- filePath,
275
- fileType,
276
- violations,
277
- imports,
278
- passed: violations.length === 0,
279
- };
280
- }
281
-
282
- /**
283
- * Analyze multiple files for platform import violations
284
- *
285
- * @param files - Array of files to analyze
286
- * @param options - Analyzer options
287
- * @returns Array of analysis results
288
- *
289
- * @example
290
- * ```typescript
291
- * const results = analyzeFiles(
292
- * [
293
- * { path: 'Button.tsx', content: buttonSource },
294
- * { path: 'Button.web.tsx', content: webSource },
295
- * { path: 'Button.native.tsx', content: nativeSource },
296
- * ],
297
- * { severity: 'warning' }
298
- * );
299
- *
300
- * const failed = results.filter(r => !r.passed);
301
- * ```
302
- */
303
- export function analyzeFiles(
304
- files: FileInput[],
305
- options?: AnalyzerOptions
306
- ): AnalysisResult[] {
307
- return files.map((file) =>
308
- analyzePlatformImports(file.path, file.content, options)
309
- );
310
- }
311
-
312
- /**
313
- * Get a summary of analysis results
314
- */
315
- export interface AnalysisSummary {
316
- totalFiles: number;
317
- passedFiles: number;
318
- failedFiles: number;
319
- totalViolations: number;
320
- violationsByType: Record<ViolationType, number>;
321
- violationsBySeverity: Record<Severity, number>;
322
- }
323
-
324
- /**
325
- * Summarize analysis results
326
- *
327
- * @param results - Array of analysis results
328
- * @returns Summary statistics
329
- */
330
- export function summarizeResults(results: AnalysisResult[]): AnalysisSummary {
331
- const violationsByType: Record<ViolationType, number> = {
332
- 'native-in-shared': 0,
333
- 'dom-in-shared': 0,
334
- 'native-in-web': 0,
335
- 'dom-in-native': 0,
336
- };
337
-
338
- const violationsBySeverity: Record<Severity, number> = {
339
- error: 0,
340
- warning: 0,
341
- info: 0,
342
- };
343
-
344
- let totalViolations = 0;
345
-
346
- for (const result of results) {
347
- for (const violation of result.violations) {
348
- totalViolations++;
349
- violationsByType[violation.type]++;
350
- violationsBySeverity[violation.severity]++;
351
- }
352
- }
353
-
354
- return {
355
- totalFiles: results.length,
356
- passedFiles: results.filter((r) => r.passed).length,
357
- failedFiles: results.filter((r) => !r.passed).length,
358
- totalViolations,
359
- violationsByType,
360
- violationsBySeverity,
361
- };
362
- }
363
-
364
- /**
365
- * Format a violation for console output
366
- */
367
- export function formatViolation(violation: Violation): string {
368
- const severityPrefix =
369
- violation.severity === 'error'
370
- ? 'ERROR'
371
- : violation.severity === 'warning'
372
- ? 'WARN'
373
- : 'INFO';
374
-
375
- return `${severityPrefix}: ${violation.filePath}:${violation.line}:${violation.column} - ${violation.message}`;
376
- }
377
-
378
- /**
379
- * Format all violations from results for console output
380
- */
381
- export function formatViolations(results: AnalysisResult[]): string[] {
382
- const lines: string[] = [];
383
-
384
- for (const result of results) {
385
- for (const violation of result.violations) {
386
- lines.push(formatViolation(violation));
387
- }
388
- }
389
-
390
- return lines;
391
- }
package/src/index.ts DELETED
@@ -1,156 +0,0 @@
1
- /**
2
- * @idealyst/tooling
3
- *
4
- * Code analysis and validation utilities for Idealyst Framework.
5
- * Provides tools for babel plugins, CLI, and MCP to validate cross-platform code.
6
- *
7
- * Also provides component documentation generation:
8
- * - analyzeComponents(): Generate a component registry from TypeScript source
9
- * - analyzeTheme(): Extract theme values (intents, sizes, etc.)
10
- * - idealystDocsPlugin(): Vite plugin for virtual module support
11
- */
12
-
13
- // Types
14
- export * from './types';
15
-
16
- // Component Documentation (also available via @idealyst/tooling/docs)
17
- export {
18
- analyzeComponents,
19
- analyzeTheme,
20
- // Babel plugin compatibility
21
- loadThemeKeys,
22
- resetThemeCache,
23
- type BabelThemeKeys,
24
- // Types
25
- type ComponentRegistry,
26
- type ComponentDefinition,
27
- type PropDefinition,
28
- type ThemeValues,
29
- type ComponentAnalyzerOptions,
30
- type SampleProps,
31
- type ControlledState,
32
- } from './analyzer';
33
-
34
- // Vite Plugin (also available via @idealyst/tooling/vite)
35
- export { idealystDocsPlugin, generateComponentRegistry } from './vite-plugin';
36
- export type { IdealystDocsPluginOptions } from './analyzer/types';
37
-
38
- // Analyzers
39
- export {
40
- // Platform import analysis
41
- analyzePlatformImports,
42
- analyzeFiles,
43
- summarizeResults,
44
- formatViolation,
45
- formatViolations,
46
- type AnalysisSummary,
47
- // Component linting (catches issues TypeScript can't)
48
- lintComponent,
49
- lintComponents,
50
- formatLintIssue,
51
- formatLintResults,
52
- summarizeLintResults,
53
- type LintIssueType,
54
- type LintIssue,
55
- type LintResult,
56
- type LintSummary,
57
- type ComponentLinterOptions,
58
- } from './analyzers';
59
-
60
- // Rules
61
- export {
62
- // React Native
63
- REACT_NATIVE_SOURCES,
64
- REACT_NATIVE_PRIMITIVES,
65
- REACT_NATIVE_PRIMITIVE_NAMES,
66
- REACT_NATIVE_RULE_SET,
67
- isReactNativePrimitive,
68
- getReactNativePrimitive,
69
- // React DOM
70
- REACT_DOM_SOURCES,
71
- REACT_DOM_PRIMITIVES,
72
- REACT_DOM_PRIMITIVE_NAMES,
73
- REACT_DOM_RULE_SET,
74
- HTML_INTRINSIC_ELEMENTS,
75
- HTML_ELEMENT_NAMES,
76
- isReactDomPrimitive,
77
- isHtmlElement,
78
- getReactDomPrimitive,
79
- } from './rules';
80
-
81
- // Utilities
82
- export {
83
- classifyFile,
84
- isComponentFile,
85
- isSharedFile,
86
- isPlatformSpecificFile,
87
- getExpectedPlatform,
88
- getBaseName,
89
- parseImports,
90
- getPlatformForSource,
91
- filterPlatformImports,
92
- getUniqueSources,
93
- groupImportsBySource,
94
- type ImportParserOptions,
95
- } from './utils';
96
-
97
- // =============================================================================
98
- // Runtime Placeholders - These get replaced by the Vite plugin at build time
99
- // =============================================================================
100
-
101
- import type { ComponentRegistry } from './analyzer/types';
102
-
103
- /**
104
- * Component registry placeholder.
105
- * This empty object is replaced at build time by the idealystDocsPlugin
106
- * with the actual component metadata extracted from your codebase.
107
- *
108
- * @example
109
- * ```ts
110
- * import { componentRegistry } from '@idealyst/tooling';
111
- *
112
- * // Access component definitions
113
- * const buttonDef = componentRegistry['Button'];
114
- * console.log(buttonDef.description);
115
- * console.log(buttonDef.props);
116
- * ```
117
- */
118
- export const componentRegistry: ComponentRegistry = {};
119
-
120
- /**
121
- * List of all component names in the registry.
122
- * Replaced at build time by the Vite plugin.
123
- */
124
- export const componentNames: string[] = [];
125
-
126
- /**
127
- * Get components filtered by category.
128
- * Replaced at build time by the Vite plugin.
129
- */
130
- export function getComponentsByCategory(category: string): string[] {
131
- return Object.entries(componentRegistry)
132
- .filter(([_, def]) => def.category === category)
133
- .map(([name]) => name);
134
- }
135
-
136
- /**
137
- * Get prop configuration for a component (useful for playgrounds).
138
- * Replaced at build time by the Vite plugin.
139
- */
140
- export function getPropConfig(componentName: string): Record<string, any> {
141
- const def = componentRegistry[componentName];
142
- if (!def) return {};
143
-
144
- return Object.entries(def.props).reduce((acc, [key, prop]) => {
145
- if (prop.values && prop.values.length > 0) {
146
- acc[key] = { type: 'select', options: prop.values, default: prop.default };
147
- } else if (prop.type === 'boolean') {
148
- acc[key] = { type: 'boolean', default: prop.default ?? false };
149
- } else if (prop.type === 'string') {
150
- acc[key] = { type: 'text', default: prop.default ?? '' };
151
- } else if (prop.type === 'number') {
152
- acc[key] = { type: 'number', default: prop.default ?? 0 };
153
- }
154
- return acc;
155
- }, {} as Record<string, any>);
156
- }
@@ -1,2 +0,0 @@
1
- export * from './reactNativePrimitives';
2
- export * from './reactDomPrimitives';