@fragments-sdk/cli 0.15.0 → 0.15.2
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/{ai-client-I6MDWNYA.js → ai-client-LSLQGOMM.js} +1 -2
- package/dist/bin.js +565 -548
- package/dist/bin.js.map +1 -1
- package/dist/chunk-5JF26E55.js +1255 -0
- package/dist/chunk-5JF26E55.js.map +1 -0
- package/dist/{chunk-XJQ5BIWI.js → chunk-6SQPP47U.js} +30 -314
- package/dist/chunk-6SQPP47U.js.map +1 -0
- package/dist/{chunk-65WSVDV5.js → chunk-HQ6A6DTV.js} +1386 -1097
- package/dist/chunk-HQ6A6DTV.js.map +1 -0
- package/dist/chunk-MHIBEEW4.js +511 -0
- package/dist/chunk-MHIBEEW4.js.map +1 -0
- package/dist/{chunk-CZD3AD4Q.js → chunk-ONUP6Z4W.js} +17 -6
- package/dist/chunk-ONUP6Z4W.js.map +1 -0
- package/dist/{codebase-scanner-VOTPXRYW.js → codebase-scanner-MQHUZC2G.js} +1 -2
- package/dist/{converter-JLINP7CJ.js → converter-7XM3Y6NJ.js} +1 -2
- package/dist/{converter-JLINP7CJ.js.map → converter-7XM3Y6NJ.js.map} +1 -1
- package/dist/core/index.js +0 -1
- package/dist/create-JVAU3YKN.js +852 -0
- package/dist/create-JVAU3YKN.js.map +1 -0
- package/dist/doctor-BDPMYYE6.js +385 -0
- package/dist/doctor-BDPMYYE6.js.map +1 -0
- package/dist/{generate-A4FP5426.js → generate-PVOLUAAC.js} +3 -4
- package/dist/{generate-A4FP5426.js.map → generate-PVOLUAAC.js.map} +1 -1
- package/dist/{govern-scan-UCBZR6D6.js → govern-scan-OYFZYOQW.js} +142 -9
- package/dist/govern-scan-OYFZYOQW.js.map +1 -0
- package/dist/index.d.ts +2 -22
- package/dist/index.js +8 -7
- package/dist/index.js.map +1 -1
- package/dist/{init-HGSM35XA.js → init-SSGUSP7Z.js} +3 -4
- package/dist/{init-HGSM35XA.js.map → init-SSGUSP7Z.js.map} +1 -1
- package/dist/{init-cloud-MQ6GRJAZ.js → init-cloud-3DNKPWFB.js} +29 -4
- package/dist/{init-cloud-MQ6GRJAZ.js.map → init-cloud-3DNKPWFB.js.map} +1 -1
- package/dist/mcp-bin.js +1 -2
- package/dist/mcp-bin.js.map +1 -1
- package/dist/node-37AUE74M.js +65 -0
- package/dist/push-contracts-WY32TFP6.js +84 -0
- package/dist/push-contracts-WY32TFP6.js.map +1 -0
- package/dist/{scan-VNNKACG2.js → scan-PKSYSTRR.js} +5 -5
- package/dist/{scan-generate-TWRHNU5M.js → scan-generate-VY27PIOX.js} +8 -9
- package/dist/scan-generate-VY27PIOX.js.map +1 -0
- package/dist/{scanner-7LAZYPWZ.js → scanner-4KZNOXAK.js} +1 -2
- package/dist/{service-FHQU7YS7.js → service-QJGWUIVL.js} +16 -9
- package/dist/{snapshot-KQEQ6XHL.js → snapshot-WIJMEIFT.js} +1 -2
- package/dist/{snapshot-KQEQ6XHL.js.map → snapshot-WIJMEIFT.js.map} +1 -1
- package/dist/{static-viewer-63PG6FWY.js → static-viewer-7QIBQZRC.js} +1 -2
- package/dist/{test-UQYUCZIS.js → test-64Z5BKBA.js} +2 -3
- package/dist/{test-UQYUCZIS.js.map → test-64Z5BKBA.js.map} +1 -1
- package/dist/token-normalizer-TEPOVBPV.js +312 -0
- package/dist/token-normalizer-TEPOVBPV.js.map +1 -0
- package/dist/token-parser-32KOIOFN.js +22 -0
- package/dist/token-parser-32KOIOFN.js.map +1 -0
- package/dist/{tokens-6GYKDV6U.js → tokens-NZWFQIAB.js} +7 -7
- package/dist/{tokens-generate-VTZV5EEW.js → tokens-generate-5JQSJ27E.js} +1 -2
- package/dist/{tokens-generate-VTZV5EEW.js.map → tokens-generate-5JQSJ27E.js.map} +1 -1
- package/dist/tokens-push-HY3KO36V.js +148 -0
- package/dist/tokens-push-HY3KO36V.js.map +1 -0
- package/package.json +18 -16
- package/src/bin.ts +94 -1
- package/src/commands/__fixtures__/shadcn-label-wrapper/src/components/ui/label.contract.json +1 -1
- package/src/commands/__fixtures__/shadcn-label-wrapper/src/components/ui/primitive.contract.json +1 -1
- package/src/commands/__tests__/build-freshness.test.ts +231 -0
- package/src/commands/__tests__/create.test.ts +71 -0
- package/src/commands/__tests__/drift-sync.test.ts +1 -1
- package/src/commands/__tests__/govern.test.ts +258 -0
- package/src/commands/__tests__/init.test.ts +9 -1
- package/src/commands/__tests__/scan-generate.test.ts +1 -1
- package/src/commands/build.ts +54 -1
- package/src/commands/context.ts +1 -1
- package/src/commands/create.ts +590 -0
- package/src/commands/doctor.ts +3 -2
- package/src/commands/govern-scan.ts +187 -8
- package/src/commands/govern.ts +65 -2
- package/src/commands/init-cloud.ts +32 -4
- package/src/commands/push-contracts.ts +112 -0
- package/src/commands/scan-generate.ts +1 -1
- package/src/commands/scan.ts +13 -0
- package/src/commands/sync.ts +2 -2
- package/src/commands/tokens-push.ts +199 -0
- package/src/core/__tests__/token-resolver.test.ts +1 -1
- package/src/core/component-extractor.test.ts +1 -1
- package/src/core/drift-verifier.ts +1 -1
- package/src/core/extractor-adapter.ts +1 -1
- package/src/index.ts +3 -3
- package/src/migrate/fragment-to-contract.ts +2 -2
- package/src/service/index.ts +8 -0
- package/src/service/tailwind-v4-parser.ts +314 -0
- package/src/service/token-parser.ts +56 -0
- package/src/setup.ts +10 -39
- package/src/theme/__tests__/component-contrast.test.ts +2 -2
- package/src/theme/__tests__/serializer.test.ts +1 -1
- package/src/theme/generator.ts +30 -1
- package/src/theme/schema.ts +8 -0
- package/src/theme/serializer.ts +13 -9
- package/src/theme/types.ts +8 -0
- package/src/validators.ts +1 -2
- package/dist/chunk-65WSVDV5.js.map +0 -1
- package/dist/chunk-7WHVW72L.js +0 -2664
- package/dist/chunk-7WHVW72L.js.map +0 -1
- package/dist/chunk-CZD3AD4Q.js.map +0 -1
- package/dist/chunk-MN3TJ3D5.js +0 -695
- package/dist/chunk-MN3TJ3D5.js.map +0 -1
- package/dist/chunk-XJQ5BIWI.js.map +0 -1
- package/dist/chunk-Z7EY4VHE.js +0 -50
- package/dist/govern-scan-UCBZR6D6.js.map +0 -1
- package/dist/sass.node-4XJK6YBF.js +0 -130708
- package/dist/sass.node-4XJK6YBF.js.map +0 -1
- package/dist/scan-generate-TWRHNU5M.js.map +0 -1
- package/src/build.ts +0 -736
- package/src/core/auto-props.ts +0 -464
- package/src/core/component-extractor.ts +0 -1121
- package/src/core/token-resolver.ts +0 -155
- package/src/viewer/preview-adapter.ts +0 -116
- /package/dist/{ai-client-I6MDWNYA.js.map → ai-client-LSLQGOMM.js.map} +0 -0
- /package/dist/{chunk-Z7EY4VHE.js.map → codebase-scanner-MQHUZC2G.js.map} +0 -0
- /package/dist/{codebase-scanner-VOTPXRYW.js.map → node-37AUE74M.js.map} +0 -0
- /package/dist/{scan-VNNKACG2.js.map → scan-PKSYSTRR.js.map} +0 -0
- /package/dist/{scanner-7LAZYPWZ.js.map → scanner-4KZNOXAK.js.map} +0 -0
- /package/dist/{service-FHQU7YS7.js.map → service-QJGWUIVL.js.map} +0 -0
- /package/dist/{static-viewer-63PG6FWY.js.map → static-viewer-7QIBQZRC.js.map} +0 -0
- /package/dist/{tokens-6GYKDV6U.js.map → tokens-NZWFQIAB.js.map} +0 -0
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Token Resolver — resolves unresolved SCSS token values using actual sass compilation.
|
|
3
|
-
*
|
|
4
|
-
* The regex-based resolver in token-parser.ts cannot handle SCSS module namespaces,
|
|
5
|
-
* functions (color.scale, math.div), or map lookups. This module provides a fallback
|
|
6
|
-
* that compiles the actual SCSS sources to extract computed CSS custom property values.
|
|
7
|
-
*
|
|
8
|
-
* Used at build time only — no runtime sass dependency in the MCP server.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import { resolve, dirname, basename } from 'node:path';
|
|
12
|
-
import { existsSync, readdirSync } from 'node:fs';
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Round fractional RGB channel values produced by Sass color math.
|
|
16
|
-
*
|
|
17
|
-
* Sass functions like color.scale() and color.adjust() can produce
|
|
18
|
-
* fractional values like rgb(217.8, 217.8, 217.8). This normalizes
|
|
19
|
-
* them to clean integers: rgb(218, 218, 218).
|
|
20
|
-
*
|
|
21
|
-
* Alpha channels in rgba() are preserved as-is (they're legitimately fractional).
|
|
22
|
-
*/
|
|
23
|
-
function roundRgbValues(value: string): string {
|
|
24
|
-
return value
|
|
25
|
-
.replace(
|
|
26
|
-
/rgb\(([^)]+)\)/g,
|
|
27
|
-
(_full, inner: string) => {
|
|
28
|
-
const parts = inner.split(',').map(p => p.trim());
|
|
29
|
-
const rounded = parts.map(p => {
|
|
30
|
-
const num = parseFloat(p);
|
|
31
|
-
return isNaN(num) ? p : String(Math.round(num));
|
|
32
|
-
});
|
|
33
|
-
return `rgb(${rounded.join(', ')})`;
|
|
34
|
-
},
|
|
35
|
-
)
|
|
36
|
-
.replace(
|
|
37
|
-
/rgba\(([^)]+)\)/g,
|
|
38
|
-
(_full, inner: string) => {
|
|
39
|
-
const parts = inner.split(',').map(p => p.trim());
|
|
40
|
-
// Round RGB channels (first 3), preserve alpha as-is
|
|
41
|
-
const rounded = parts.map((p, i) => {
|
|
42
|
-
if (i >= 3) return p; // alpha channel — don't round
|
|
43
|
-
const num = parseFloat(p);
|
|
44
|
-
return isNaN(num) ? p : String(Math.round(num));
|
|
45
|
-
});
|
|
46
|
-
return `rgba(${rounded.join(', ')})`;
|
|
47
|
-
},
|
|
48
|
-
);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Resolve unresolved SCSS token values by compiling the project's token SCSS.
|
|
53
|
-
*
|
|
54
|
-
* Generates a temporary SCSS string that imports the project's _variables.scss
|
|
55
|
-
* and includes the fui-css-variables mixin, then compiles it with sass to extract
|
|
56
|
-
* the actual computed values for all CSS custom properties.
|
|
57
|
-
*
|
|
58
|
-
* @param unresolvedTokens - Tokens with values containing #{} or $ that need resolution
|
|
59
|
-
* @param tokensDir - Absolute path to the directory containing _variables.scss
|
|
60
|
-
* @returns Map of token name → resolved CSS value (only for tokens that were unresolved)
|
|
61
|
-
*/
|
|
62
|
-
export async function resolveTokensWithSass(
|
|
63
|
-
unresolvedTokens: Array<{ name: string; value: string }>,
|
|
64
|
-
tokensDir: string,
|
|
65
|
-
): Promise<Map<string, string>> {
|
|
66
|
-
const resolvedMap = new Map<string, string>();
|
|
67
|
-
|
|
68
|
-
// Filter to only tokens that actually need resolution
|
|
69
|
-
const needsResolution = unresolvedTokens.filter(
|
|
70
|
-
t => t.value.includes('#{') || t.value.includes('$'),
|
|
71
|
-
);
|
|
72
|
-
|
|
73
|
-
if (needsResolution.length === 0) {
|
|
74
|
-
return resolvedMap;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
try {
|
|
78
|
-
// Dynamic import so sass is only loaded when needed (build-time only)
|
|
79
|
-
const sass = await import('sass');
|
|
80
|
-
|
|
81
|
-
// Find the _variables.scss file and determine the mixin name
|
|
82
|
-
const variablesPath = findVariablesFile(tokensDir);
|
|
83
|
-
if (!variablesPath) {
|
|
84
|
-
return resolvedMap;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// Determine the module name for @use (filename without _ prefix and .scss suffix)
|
|
88
|
-
const fileName = basename(variablesPath);
|
|
89
|
-
const moduleName = fileName.replace(/^_/, '').replace(/\.scss$/, '');
|
|
90
|
-
|
|
91
|
-
// Generate a SCSS string that imports the variables and includes the mixin
|
|
92
|
-
const scssSource = `
|
|
93
|
-
@use '${moduleName}' as vars;
|
|
94
|
-
:root { @include vars.fui-css-variables; }
|
|
95
|
-
`;
|
|
96
|
-
|
|
97
|
-
// Compile the SCSS with the tokens directory as a load path
|
|
98
|
-
const compiled = sass.compileString(scssSource, {
|
|
99
|
-
loadPaths: [tokensDir, dirname(tokensDir)],
|
|
100
|
-
style: 'expanded',
|
|
101
|
-
// Suppress sass deprecation warnings during build
|
|
102
|
-
logger: { warn() {}, debug() {} } as never,
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
// Parse the compiled CSS for --fui-* custom property declarations
|
|
106
|
-
const cssVarRegex = /(--[\w-]+)\s*:\s*([^;]+)/g;
|
|
107
|
-
let match: RegExpExecArray | null;
|
|
108
|
-
const allResolved = new Map<string, string>();
|
|
109
|
-
|
|
110
|
-
while ((match = cssVarRegex.exec(compiled.css)) !== null) {
|
|
111
|
-
allResolved.set(match[1], roundRgbValues(match[2].trim()));
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// Only return values for the tokens that were originally unresolved
|
|
115
|
-
for (const token of needsResolution) {
|
|
116
|
-
const value = allResolved.get(token.name);
|
|
117
|
-
if (value !== undefined) {
|
|
118
|
-
resolvedMap.set(token.name, value);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
} catch {
|
|
122
|
-
// Sass compilation failure is non-fatal — fall back to regex-resolved values
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
return resolvedMap;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Find the _variables.scss file in the tokens directory.
|
|
130
|
-
*/
|
|
131
|
-
function findVariablesFile(tokensDir: string): string | null {
|
|
132
|
-
const candidates = ['_variables.scss', 'variables.scss'];
|
|
133
|
-
for (const name of candidates) {
|
|
134
|
-
const path = resolve(tokensDir, name);
|
|
135
|
-
if (existsSync(path)) {
|
|
136
|
-
return path;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// Fallback: look for any SCSS file containing 'css-variables' mixin
|
|
141
|
-
try {
|
|
142
|
-
const files = readdirSync(tokensDir).filter(f => f.endsWith('.scss'));
|
|
143
|
-
for (const file of files) {
|
|
144
|
-
const path = resolve(tokensDir, file);
|
|
145
|
-
// We just need to find it exists; the @use import will handle the rest
|
|
146
|
-
if (file.includes('variables') || file.includes('tokens')) {
|
|
147
|
-
return path;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
} catch {
|
|
151
|
-
// Directory read failure
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
return null;
|
|
155
|
-
}
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Preview Adapter — generates render modules from contract.json metadata.
|
|
3
|
-
*
|
|
4
|
-
* Each adapter takes a CompiledFragment sourced from a .contract.json
|
|
5
|
-
* and produces a virtual ES module string that a bundler (Vite) can serve.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import type { CompiledFragment } from '@fragments-sdk/core';
|
|
9
|
-
|
|
10
|
-
export interface PreviewConfig {
|
|
11
|
-
setupModule?: string;
|
|
12
|
-
wrapperModule?: string;
|
|
13
|
-
wrapperExport?: string;
|
|
14
|
-
css?: string[];
|
|
15
|
-
theme?: 'light' | 'dark';
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export interface PreviewAdapter {
|
|
19
|
-
framework: string;
|
|
20
|
-
canHandle(fragment: CompiledFragment): boolean;
|
|
21
|
-
generateRenderModule(
|
|
22
|
-
fragment: CompiledFragment,
|
|
23
|
-
variant: string,
|
|
24
|
-
previewConfig: PreviewConfig,
|
|
25
|
-
): string;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* React preview adapter — generates a virtual module that:
|
|
30
|
-
* 1. Imports the component from sourcePath/exportName
|
|
31
|
-
* 2. Wraps with providers from project config
|
|
32
|
-
* 3. Renders with args from the selected example
|
|
33
|
-
* 4. Injects CSS from config
|
|
34
|
-
*/
|
|
35
|
-
class ReactPreviewAdapter implements PreviewAdapter {
|
|
36
|
-
framework = 'react';
|
|
37
|
-
|
|
38
|
-
canHandle(fragment: CompiledFragment): boolean {
|
|
39
|
-
return (fragment.framework ?? 'react') === 'react';
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
generateRenderModule(
|
|
43
|
-
fragment: CompiledFragment,
|
|
44
|
-
variant: string,
|
|
45
|
-
config: PreviewConfig,
|
|
46
|
-
): string {
|
|
47
|
-
if (!fragment.sourcePath || !fragment.exportName) {
|
|
48
|
-
throw new Error(
|
|
49
|
-
`Cannot preview ${fragment.meta.name}: missing sourcePath or exportName`,
|
|
50
|
-
);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const example = fragment.variants.find((v) => v.name === variant) ??
|
|
54
|
-
fragment.variants[0];
|
|
55
|
-
|
|
56
|
-
const args = example?.args ?? {};
|
|
57
|
-
const argsStr = JSON.stringify(args);
|
|
58
|
-
|
|
59
|
-
const lines: string[] = [];
|
|
60
|
-
|
|
61
|
-
// Setup module (global CSS, MSW, etc.)
|
|
62
|
-
if (config.setupModule) {
|
|
63
|
-
lines.push(`import '${config.setupModule}';`);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// CSS imports
|
|
67
|
-
if (config.css?.length) {
|
|
68
|
-
for (const css of config.css) {
|
|
69
|
-
lines.push(`import '${css}';`);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// Import React
|
|
74
|
-
lines.push(`import React from 'react';`);
|
|
75
|
-
|
|
76
|
-
// Import the component
|
|
77
|
-
lines.push(`import { ${fragment.exportName} } from '${fragment.sourcePath}';`);
|
|
78
|
-
|
|
79
|
-
// Import wrapper if configured
|
|
80
|
-
if (config.wrapperModule && config.wrapperExport) {
|
|
81
|
-
lines.push(`import { ${config.wrapperExport} } from '${config.wrapperModule}';`);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// Generate the render function
|
|
85
|
-
lines.push('');
|
|
86
|
-
lines.push(`const args = ${argsStr};`);
|
|
87
|
-
lines.push('');
|
|
88
|
-
lines.push('export default function PreviewRender() {');
|
|
89
|
-
|
|
90
|
-
if (config.wrapperModule && config.wrapperExport) {
|
|
91
|
-
lines.push(` return React.createElement(${config.wrapperExport}, null,`);
|
|
92
|
-
lines.push(` React.createElement(${fragment.exportName}, args)`);
|
|
93
|
-
lines.push(' );');
|
|
94
|
-
} else {
|
|
95
|
-
lines.push(` return React.createElement(${fragment.exportName}, args);`);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
lines.push('}');
|
|
99
|
-
|
|
100
|
-
return lines.join('\n');
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Create a preview adapter for the given framework.
|
|
106
|
-
*/
|
|
107
|
-
export function createPreviewAdapter(
|
|
108
|
-
framework: string,
|
|
109
|
-
_config: PreviewConfig,
|
|
110
|
-
): PreviewAdapter {
|
|
111
|
-
if (framework === 'react') {
|
|
112
|
-
return new ReactPreviewAdapter();
|
|
113
|
-
}
|
|
114
|
-
// Future: Vue, Svelte adapters
|
|
115
|
-
throw new Error(`No preview adapter available for framework: ${framework}`);
|
|
116
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|