@frontfriend/tailwind 2.1.0 → 2.1.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/cli.js +61 -19
- package/dist/lib/vue/utils.d.ts +8 -6
- package/dist/runtime.d.ts +3 -1
- package/dist/scripts/generate-icon-types.js +141 -0
- package/dist/types/index.d.ts +1 -1
- package/package.json +2 -1
- package/scripts/build.js +371 -0
- package/scripts/generate-icon-types.js +141 -0
package/dist/cli.js
CHANGED
|
@@ -1,23 +1,65 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
var{
|
|
3
|
-
`);let
|
|
2
|
+
var O=(e,n)=>()=>(n||e((n={exports:{}}).exports,n),n.exports);var S=O((V,I)=>{var u=require("fs"),F=require("path");function D(){let e=process.cwd(),n=F.join(e,"node_modules",".cache","frontfriend","icons.json"),o=F.join(e,"types","frontfriend-icons.d.ts");u.existsSync(n)||(console.error('[FrontFriend] Error: icons.json not found. Please run "npx frontfriend setup" first.'),process.exit(1));try{let r=function(t){for(let i of Object.values(t))typeof i=="string"?s.add(i):typeof i=="object"&&i!==null&&r(i)},g=function(t,i=" "){let f=[];for(let[k,h]of Object.entries(t))typeof h=="string"?f.push(`${i}${k}: '${h}';`):typeof h=="object"&&h!==null&&(f.push(`${i}${k}: {`),f.push(g(h,i+" ")),f.push(`${i}};`));return f.join(`
|
|
3
|
+
`)};var a=r,c=g;let l=JSON.parse(u.readFileSync(n,"utf-8")),s=new Set;r(l);let p=Array.from(s).map(t=>`'${t}'`).join(" | "),y=`// Generated by @frontfriend/tailwind
|
|
4
|
+
// DO NOT EDIT THIS FILE MANUALLY
|
|
5
|
+
|
|
6
|
+
import type { IconSetStructure } from '@frontfriend/tailwind';
|
|
7
|
+
|
|
8
|
+
declare module '@frontfriend/tailwind' {
|
|
9
|
+
// Icon names used in this project
|
|
10
|
+
export type ProjectIconName = ${p||"string"};
|
|
11
|
+
|
|
12
|
+
// Typed iconSet structure with exact icon names
|
|
13
|
+
export interface TypedIconSet extends IconSetStructure {
|
|
14
|
+
${g(l)}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Override the iconSet type with the typed version
|
|
18
|
+
export const iconSet: TypedIconSet;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Augment Vue component types with exact icon names
|
|
22
|
+
declare module '*/components/ui/icon/*.vue' {
|
|
23
|
+
export type IconName = ${p||"string"};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
declare module '@/components/ui/icon/*.vue' {
|
|
27
|
+
export type IconName = ${p||"string"};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
declare module '@/components/ui/icon' {
|
|
31
|
+
export type IconName = ${p||"string"};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
declare module '@/src/components/ui/icon' {
|
|
35
|
+
export type IconName = ${p||"string"};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
declare module '@/src/components/ui/icon/Icon.vue' {
|
|
39
|
+
export type IconName = ${p||"string"};
|
|
40
|
+
}
|
|
41
|
+
`,$=F.dirname(o);u.existsSync($)||u.mkdirSync($,{recursive:!0}),u.writeFileSync(o,y),console.log("[FrontFriend] \u2713 Generated icon types at types/frontfriend-icons.d.ts");let w=F.join(e,"tsconfig.json");if(u.existsSync(w)){let t=JSON.parse(u.readFileSync(w,"utf-8"));t.include||(t.include=[]);let i="types/**/*.d.ts";t.include.includes(i)||(t.include.push(i),u.writeFileSync(w,JSON.stringify(t,null,2)),console.log("[FrontFriend] \u2713 Updated tsconfig.json to include generated types"))}}catch(l){console.error("[FrontFriend] Error generating icon types:",l.message),process.exit(1)}}require.main===I&&D();I.exports={generateIconTypes:D}});var{Command:L}=require("commander"),x=require("./lib/config/config-loader"),j=require("./lib/config/cache-manager"),{APIClient:R}=require("./lib/core/api-client"),{ComponentDownloader:q}=require("./lib/core/component-downloader"),N=require("./lib/core/token-processor"),{ConfigError:C,APIError:E,CacheError:T}=require("./lib/core/errors"),b=require("path"),m=new L;m.name("frontfriend").description("FrontFriend Tailwind CLI - Manage design tokens and cache").version("2.0.0");m.command("init").description("Initialize FrontFriend configuration and fetch from API").option("--force","Force refresh even if cache is valid").action(async e=>{try{console.log("\u{1F527} FrontFriend Setup"),console.log(`==================
|
|
42
|
+
`);let o=await new x().load();if(!o.ffId)throw new C(`ff-id not found in frontfriend.config.js
|
|
4
43
|
Please add "ff-id" to your frontfriend.config.js file`,"ff-id");console.log("\u{1F4CB} Configuration loaded"),console.log(` FF_ID: ${o.ffId}`),console.log(` App Root: ${o.appRoot}
|
|
5
|
-
`);let
|
|
6
|
-
`):
|
|
44
|
+
`);let a=new j(o.appRoot);!e.force&&a.exists()&&a.isValid()&&(console.log("\u2705 Cache is valid and up to date"),console.log(" Use --force to refresh anyway"),process.exit(0)),console.log("\u{1F50D} Checking cache..."),e.force?console.log(` Force refresh requested
|
|
45
|
+
`):a.exists()?console.log(` Cache expired
|
|
7
46
|
`):console.log(` No cache found
|
|
8
|
-
`),console.log("\u{1F310} Fetching configuration...");let c=new
|
|
9
|
-
`),console.log("\u{1F4BE} Saving cache..."),
|
|
10
|
-
`),console.log("\u2705 Setup complete!"),console.log(" Your FrontFriend configuration has been cached."),console.log(" The Tailwind plugin will now use this cached data."),
|
|
11
|
-
|
|
12
|
-
`),
|
|
13
|
-
`);let
|
|
14
|
-
`),console.log("\
|
|
15
|
-
`)
|
|
16
|
-
|
|
17
|
-
`);let
|
|
18
|
-
`);let
|
|
19
|
-
|
|
20
|
-
`);let
|
|
21
|
-
|
|
22
|
-
|
|
47
|
+
`),console.log("\u{1F310} Fetching configuration...");let c=new R(o.ffId,{baseURL:o["api-url"]||o.apiUrl});(o["api-url"]||o.apiUrl)&&console.log(` Using API URL: ${o["api-url"]||o.apiUrl}`);let l=null;try{l=await c.fetchProcessedTokens()}catch(d){console.log(` \u26A0\uFE0F Failed to fetch pre-processed tokens: ${d.message}`)}if(l){console.log(" \u2713 Pre-processed tokens fetched from server"),console.log(` \u2713 Skipping local processing
|
|
48
|
+
`),console.log("\u{1F4BE} Saving cache..."),a.save(l),console.log(` \u2713 Cache saved successfully
|
|
49
|
+
`),console.log("\u2705 Setup complete!"),console.log(" Your FrontFriend configuration has been cached."),console.log(" The Tailwind plugin will now use this cached data.");let d=require("fs"),P=b.join(o.appRoot,"tsconfig.json");if(d.existsSync(P)){console.log(`
|
|
50
|
+
\u{1F524} Generating TypeScript types...`);try{let{generateIconTypes:v}=S();v()}catch(v){console.log(" \u26A0\uFE0F Type generation failed:",v.message),console.log(' Run "npx frontfriend generate-types" manually to retry')}}process.exit(0)}console.log(` \u2139\uFE0F Pre-processed tokens not available, falling back to local processing
|
|
51
|
+
`);let[s,r,g,p,y,$]=await Promise.all([c.fetchTokens(),c.fetchComponentsConfig(),c.fetchFonts(),c.fetchIcons(),c.fetchVersion(),c.fetchCustomCss()]);if(console.log(" \u2713 Tokens fetched"),s.global||s.colors||s.semantic||s.semanticDark){let d=[s.global?"global":null,s.colors?"colors":null,s.semantic?"semantic":null,s.semanticDark?"semanticDark":null].filter(Boolean).join(", ");console.log(` (Found: ${d})`)}console.log(" \u2713 Components config fetched"),console.log(" \u2713 Fonts fetched"),console.log(" \u2713 Icons fetched"),console.log(" \u2713 Version fetched"),console.log(` \u2713 Custom CSS fetched
|
|
52
|
+
`),console.log("\u2699\uFE0F Processing tokens...");let w=new N;console.log(" Processing raw token data...");let t=await w.process({colors:s.colors||s.global,semantic:s.semantic,semanticDark:s.semanticDark,fonts:g,globalTokens:s.global,animations:s.animations,version:y==null?void 0:y.version,ffId:o.ffId,customCss:$});console.log(" \u2713 Colors processed"),console.log(" \u2713 Semantic tokens processed"),t.fontFaces.length>0&&console.log(` \u2713 ${t.fontFaces.length} font faces processed`),Object.keys(t.animations).length>0&&console.log(` \u2713 ${Object.keys(t.animations).length} animations processed`),console.log(`
|
|
53
|
+
`);let i=w.extractClassesFromComponentsConfig(r),f={tokens:t.utilities,variables:t.variables,semanticVariables:t.semanticVariables,semanticDarkVariables:t.semanticDarkVariables,fonts:t.fontFaces,icons:p,componentsConfig:r,keyframes:t.keyframes,animations:t.animations,safelist:t.safelist,version:y,metadata:t.metadata,cls:i||[],custom:t.custom};console.log("\u{1F4BE} Saving cache..."),console.log(" Cache data summary:"),console.log(` - Tokens: ${Object.keys(f.tokens||{}).length} utilities`),console.log(` - Variables: ${Object.keys(f.variables||{}).length} CSS variables`),console.log(` - Semantic variables: ${Object.keys(f.semanticVariables||{}).length} semantic variables`),console.log(` - Font faces: ${(f.fonts||[]).length} fonts`),console.log(` - Classes: ${(f.cls||[]).length} extracted classes`),a.save(f),console.log(` \u2713 Cache saved successfully
|
|
54
|
+
`),console.log("\u2705 Setup complete!"),console.log(" Your FrontFriend configuration has been cached."),console.log(" The Tailwind plugin will now use this cached data.");let k=require("fs"),h=b.join(o.appRoot,"tsconfig.json");if(k.existsSync(h)){console.log(`
|
|
55
|
+
\u{1F524} Generating TypeScript types...`);try{let{generateIconTypes:d}=S();d()}catch(d){console.log(" \u26A0\uFE0F Type generation failed:",d.message),console.log(' Run "npx frontfriend generate-types" manually to retry')}}process.exit(0)}catch(n){n instanceof C?console.error("\u274C Configuration Error:",n.message):n instanceof E?(console.error("\u274C API Error:",n.message),console.error(` Status: ${n.statusCode}`),console.error(` URL: ${n.url}`)):n instanceof T?(console.error("\u274C Cache Error:",n.message),console.error(` Operation: ${n.operation}`)):console.error("\u274C Setup failed:",n.message),process.exit(1)}});m.command("clean").description("Remove cached configuration").action(async()=>{try{console.log(`\u{1F9F9} Cleaning FrontFriend cache...
|
|
56
|
+
`);let n=new x().load(),o=new j(n.appRoot);o.exists()?(o.clear(),console.log("\u2705 Cache cleared successfully")):console.log("\u2139\uFE0F No cache found"),process.exit(0)}catch(e){e instanceof T?(console.error("\u274C Cache Error:",e.message),console.error(` Operation: ${e.operation}`)):console.error("\u274C Clean failed:",e.message),process.exit(1)}});m.command("generate-types").description("Generate TypeScript types from cached icons.json").action(async()=>{try{console.log(`\u{1F524} Generating TypeScript types...
|
|
57
|
+
`);let{generateIconTypes:e}=S();e(),process.exit(0)}catch(e){console.error("\u274C Type generation failed:",e.message),process.exit(1)}});m.command("status").description("Show cache status and configuration").action(async()=>{try{console.log("\u{1F4CA} FrontFriend Status"),console.log(`===================
|
|
58
|
+
`);let n=await new x().load();console.log("Configuration:"),console.log(` FF_ID: ${n.ffId||"Not set"}`),console.log(` App Root: ${n.appRoot}
|
|
59
|
+
`);let o=new j(n.appRoot),a=o.getCacheDir();if(console.log("Cache:"),console.log(` Directory: ${b.relative(process.cwd(),a)}`),o.exists()){console.log(` Status: ${o.isValid()?"\u2705 Valid":"\u26A0\uFE0F Expired"}`);let c=o.load();if(c&&c.metadata){let l=new Date(c.metadata.timestamp);console.log(` Created: ${l.toLocaleString()}`),console.log(` Version: ${c.metadata.version||"Unknown"}`)}}else console.log(" Status: \u274C Not found");process.exit(0)}catch(e){e instanceof C?console.error("\u274C Configuration Error:",e.message):e instanceof T?(console.error("\u274C Cache Error:",e.message),console.error(` Operation: ${e.operation}`)):console.error("\u274C Status check failed:",e.message),process.exit(1)}});m.command("download").description("Download components from registry").argument("<components...>",'component names to download (or "all" to download all components)').option("-f, --framework <framework>","Framework to download components for (react/vue)").option("-o, --output <path>","Output directory for components").option("--overwrite","Overwrite existing files").action(async(e,n)=>{try{console.log(`\u{1F4E6} Downloading components...
|
|
60
|
+
`);let a=await new x().load();if(!a.ffId)throw new C(`ff-id not found in frontfriend.config.js
|
|
61
|
+
Please add "ff-id" to your frontfriend.config.js file`,"ff-id");let c=new q({appRoot:a.appRoot,config:a,framework:n.framework,outputPath:n.output,overwrite:n.overwrite}),l=e;if(e.length===1&&e[0].toLowerCase()==="all"){let r=await c.getAllComponents(),g=await c.getCustomComponents();r.length===0&&(console.error("\u274C Failed to fetch component list"),process.exit(1)),l=[...r,...g],console.log("\u{1F4CB} Configuration"),console.log(` Framework: ${c.framework}`),console.log(` Output: ${c.outputPath}`),console.log(` Components: All ${r.length} standard components`),g.length>0&&console.log(` Custom: ${g.length} custom components for ff-id: ${a.ffId||a["ff-id"]}`),console.log("")}else console.log("\u{1F4CB} Configuration"),console.log(` Framework: ${c.framework}`),console.log(` Output: ${c.outputPath}`),console.log(` Components: ${e.join(", ")}
|
|
62
|
+
`);let s=await c.downloadComponents(l);s.successful.length>0&&(console.log(`
|
|
63
|
+
\u2705 Download complete!`),console.log(` Downloaded: ${s.successful.length} components`)),s.failed.length>0&&(console.log(""),s.failed.forEach(r=>{r.error.includes("not found")?console.log(`\u274C ${r.error}`):console.log(`\u274C Failed to download ${r.component}: ${r.error}`)})),s.successful.length>0&&s.dependencies.length>0&&(console.log(`
|
|
64
|
+
\u{1F4E6} Install dependencies:`),console.log(` npm install ${s.dependencies.join(" ")}`)),s.successful.length===0&&s.failed.length>0&&process.exit(1),process.exit(0)}catch(o){o instanceof C?(console.error("\u274C Configuration Error:",o.message),o.missingKey&&console.error(` Missing key: ${o.missingKey}`)):console.error("\u274C Download failed:",o.message),process.exit(1)}});m.parse(process.argv);process.argv.slice(2).length||(m.outputHelp(),process.exit(0));
|
|
23
65
|
//# sourceMappingURL=cli-temp.js.map
|
package/dist/lib/vue/utils.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { Ref, ComputedRef } from 'vue';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Combines class names with tailwind-merge
|
|
3
5
|
* @param inputs - Class names to combine
|
|
@@ -10,16 +12,16 @@ export function cn(...inputs: any[]): string;
|
|
|
10
12
|
* @param query - Media query string
|
|
11
13
|
* @returns Ref<boolean> indicating if query matches
|
|
12
14
|
*/
|
|
13
|
-
export function useMediaQuery(query: string):
|
|
15
|
+
export function useMediaQuery(query: string): Ref<boolean>;
|
|
14
16
|
|
|
15
17
|
/**
|
|
16
18
|
* Vue composition API hook for responsive breakpoints
|
|
17
19
|
* @returns Object with breakpoint states and active breakpoint
|
|
18
20
|
*/
|
|
19
21
|
export function useBreakpoints(): {
|
|
20
|
-
isXs:
|
|
21
|
-
isSm:
|
|
22
|
-
isMd:
|
|
23
|
-
isLg:
|
|
24
|
-
active:
|
|
22
|
+
isXs: Ref<boolean>;
|
|
23
|
+
isSm: Ref<boolean>;
|
|
24
|
+
isMd: Ref<boolean>;
|
|
25
|
+
isLg: Ref<boolean>;
|
|
26
|
+
active: ComputedRef<'xs' | 'sm' | 'md' | 'lg'>;
|
|
25
27
|
};
|
package/dist/runtime.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { IconSetStructure } from './types/index';
|
|
2
|
+
|
|
1
3
|
export interface FrontFriend {
|
|
2
4
|
/** Current configuration */
|
|
3
5
|
config: Record<string, any> | null;
|
|
4
6
|
/** Icon set */
|
|
5
|
-
iconSet:
|
|
7
|
+
iconSet: IconSetStructure | null;
|
|
6
8
|
/** Get an icon by name */
|
|
7
9
|
getIcon(name: string): string | null;
|
|
8
10
|
/** Refresh configuration from globals */
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Generate TypeScript types from icons.json cache file
|
|
8
|
+
* This script reads the icons.json file and generates proper types for the iconSet
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
function generateIconTypes() {
|
|
12
|
+
const projectRoot = process.cwd();
|
|
13
|
+
const iconsPath = path.join(projectRoot, 'node_modules', '.cache', 'frontfriend', 'icons.json');
|
|
14
|
+
const outputPath = path.join(projectRoot, 'types', 'frontfriend-icons.d.ts');
|
|
15
|
+
|
|
16
|
+
// Check if icons.json exists
|
|
17
|
+
if (!fs.existsSync(iconsPath)) {
|
|
18
|
+
console.error('[FrontFriend] Error: icons.json not found. Please run "npx frontfriend setup" first.');
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
// Read icons.json
|
|
24
|
+
const icons = JSON.parse(fs.readFileSync(iconsPath, 'utf-8'));
|
|
25
|
+
|
|
26
|
+
// Extract all unique icon names
|
|
27
|
+
const iconNames = new Set();
|
|
28
|
+
|
|
29
|
+
function extractIconNames(obj) {
|
|
30
|
+
for (const value of Object.values(obj)) {
|
|
31
|
+
if (typeof value === 'string') {
|
|
32
|
+
iconNames.add(value);
|
|
33
|
+
} else if (typeof value === 'object' && value !== null) {
|
|
34
|
+
extractIconNames(value);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
extractIconNames(icons);
|
|
40
|
+
|
|
41
|
+
// Generate the interface structure recursively
|
|
42
|
+
function generateInterface(obj, indent = ' ') {
|
|
43
|
+
const lines = [];
|
|
44
|
+
|
|
45
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
46
|
+
if (typeof value === 'string') {
|
|
47
|
+
lines.push(`${indent}${key}: '${value}';`);
|
|
48
|
+
} else if (typeof value === 'object' && value !== null) {
|
|
49
|
+
lines.push(`${indent}${key}: {`);
|
|
50
|
+
lines.push(generateInterface(value, indent + ' '));
|
|
51
|
+
lines.push(`${indent}};`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return lines.join('\n');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Generate the type definition file
|
|
59
|
+
const iconNameType = Array.from(iconNames).map(name => `'${name}'`).join(' | ');
|
|
60
|
+
|
|
61
|
+
const typeDefinition = `// Generated by @frontfriend/tailwind
|
|
62
|
+
// DO NOT EDIT THIS FILE MANUALLY
|
|
63
|
+
|
|
64
|
+
import type { IconSetStructure } from '@frontfriend/tailwind';
|
|
65
|
+
|
|
66
|
+
declare module '@frontfriend/tailwind' {
|
|
67
|
+
// Icon names used in this project
|
|
68
|
+
export type ProjectIconName = ${iconNameType || 'string'};
|
|
69
|
+
|
|
70
|
+
// Typed iconSet structure with exact icon names
|
|
71
|
+
export interface TypedIconSet extends IconSetStructure {
|
|
72
|
+
${generateInterface(icons)}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Override the iconSet type with the typed version
|
|
76
|
+
export const iconSet: TypedIconSet;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Augment Vue component types with exact icon names
|
|
80
|
+
declare module '*/components/ui/icon/*.vue' {
|
|
81
|
+
export type IconName = ${iconNameType || 'string'};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
declare module '@/components/ui/icon/*.vue' {
|
|
85
|
+
export type IconName = ${iconNameType || 'string'};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
declare module '@/components/ui/icon' {
|
|
89
|
+
export type IconName = ${iconNameType || 'string'};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
declare module '@/src/components/ui/icon' {
|
|
93
|
+
export type IconName = ${iconNameType || 'string'};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
declare module '@/src/components/ui/icon/Icon.vue' {
|
|
97
|
+
export type IconName = ${iconNameType || 'string'};
|
|
98
|
+
}
|
|
99
|
+
`;
|
|
100
|
+
|
|
101
|
+
// Ensure types directory exists
|
|
102
|
+
const typesDir = path.dirname(outputPath);
|
|
103
|
+
if (!fs.existsSync(typesDir)) {
|
|
104
|
+
fs.mkdirSync(typesDir, { recursive: true });
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Write the type definition file
|
|
108
|
+
fs.writeFileSync(outputPath, typeDefinition);
|
|
109
|
+
|
|
110
|
+
console.log('[FrontFriend] ✓ Generated icon types at types/frontfriend-icons.d.ts');
|
|
111
|
+
|
|
112
|
+
// Check if tsconfig.json exists and update it
|
|
113
|
+
const tsconfigPath = path.join(projectRoot, 'tsconfig.json');
|
|
114
|
+
if (fs.existsSync(tsconfigPath)) {
|
|
115
|
+
const tsconfig = JSON.parse(fs.readFileSync(tsconfigPath, 'utf-8'));
|
|
116
|
+
|
|
117
|
+
// Ensure the types file is included
|
|
118
|
+
if (!tsconfig.include) {
|
|
119
|
+
tsconfig.include = [];
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const typesPattern = 'types/**/*.d.ts';
|
|
123
|
+
if (!tsconfig.include.includes(typesPattern)) {
|
|
124
|
+
tsconfig.include.push(typesPattern);
|
|
125
|
+
fs.writeFileSync(tsconfigPath, JSON.stringify(tsconfig, null, 2));
|
|
126
|
+
console.log('[FrontFriend] ✓ Updated tsconfig.json to include generated types');
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
} catch (error) {
|
|
131
|
+
console.error('[FrontFriend] Error generating icon types:', error.message);
|
|
132
|
+
process.exit(1);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Run if called directly
|
|
137
|
+
if (require.main === module) {
|
|
138
|
+
generateIconTypes();
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
module.exports = { generateIconTypes };
|
package/dist/types/index.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frontfriend/tailwind",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.2",
|
|
4
4
|
"description": "Design token management for Tailwind CSS",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/types/index.d.ts",
|
|
@@ -53,6 +53,7 @@
|
|
|
53
53
|
"license": "SEE LICENSE IN LICENSE",
|
|
54
54
|
"files": [
|
|
55
55
|
"dist/",
|
|
56
|
+
"scripts/",
|
|
56
57
|
"README.md",
|
|
57
58
|
"LICENSE"
|
|
58
59
|
],
|
package/scripts/build.js
ADDED
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
const esbuild = require('esbuild');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const { glob } = require('glob');
|
|
5
|
+
|
|
6
|
+
// Clean dist directory
|
|
7
|
+
const distDir = path.join(__dirname, '..', 'dist');
|
|
8
|
+
if (fs.existsSync(distDir)) {
|
|
9
|
+
fs.rmSync(distDir, { recursive: true, force: true });
|
|
10
|
+
}
|
|
11
|
+
fs.mkdirSync(distDir, { recursive: true });
|
|
12
|
+
|
|
13
|
+
// Create lib subdirectories
|
|
14
|
+
fs.mkdirSync(path.join(distDir, 'lib', 'core'), { recursive: true });
|
|
15
|
+
fs.mkdirSync(path.join(distDir, 'lib', 'config'), { recursive: true });
|
|
16
|
+
fs.mkdirSync(path.join(distDir, 'lib', 'react'), { recursive: true });
|
|
17
|
+
fs.mkdirSync(path.join(distDir, 'lib', 'vue'), { recursive: true });
|
|
18
|
+
fs.mkdirSync(path.join(distDir, 'scripts'), { recursive: true });
|
|
19
|
+
|
|
20
|
+
// Copy type definitions
|
|
21
|
+
fs.mkdirSync(path.join(distDir, 'types'), { recursive: true });
|
|
22
|
+
fs.copyFileSync(
|
|
23
|
+
path.join(__dirname, '..', 'types', 'index.d.ts'),
|
|
24
|
+
path.join(distDir, 'types', 'index.d.ts')
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
// Create individual type declaration files for each export
|
|
28
|
+
const typeDeclarations = [
|
|
29
|
+
{
|
|
30
|
+
path: 'runtime.d.ts',
|
|
31
|
+
content: `import { IconSetStructure } from './types/index';
|
|
32
|
+
|
|
33
|
+
export interface FrontFriend {
|
|
34
|
+
/** Current configuration */
|
|
35
|
+
config: Record<string, any> | null;
|
|
36
|
+
/** Icon set */
|
|
37
|
+
iconSet: IconSetStructure | null;
|
|
38
|
+
/** Get an icon by name */
|
|
39
|
+
getIcon(name: string): string | null;
|
|
40
|
+
/** Refresh configuration from globals */
|
|
41
|
+
refresh(): void;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
declare const FrontFriend: FrontFriend;
|
|
45
|
+
export default FrontFriend;`
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
path: 'next.d.ts',
|
|
49
|
+
content: `import { NextConfig } from 'next';
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Wraps Next.js configuration to inject FrontFriend globals
|
|
53
|
+
* @param config - Next.js configuration object
|
|
54
|
+
* @returns Modified Next.js configuration
|
|
55
|
+
*/
|
|
56
|
+
export default function frontfriend(config?: NextConfig): NextConfig;`
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
path: 'vite.d.ts',
|
|
60
|
+
content: `import { Plugin } from 'vite';
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Vite plugin for FrontFriend globals injection
|
|
64
|
+
* @returns Vite plugin configuration
|
|
65
|
+
*/
|
|
66
|
+
export default function frontfriend(): Plugin;`
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
path: 'ffdc.d.ts',
|
|
70
|
+
content: `/**
|
|
71
|
+
* FrontFriend Design Config processor
|
|
72
|
+
* @param config - Design configuration object
|
|
73
|
+
* @returns Processed configuration
|
|
74
|
+
*/
|
|
75
|
+
export function ffdc(config: Record<string, any> | null | undefined): Record<string, any>;`
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
path: 'lib/react/utils.d.ts',
|
|
79
|
+
content: `/**
|
|
80
|
+
* Combines class names with tailwind-merge
|
|
81
|
+
* @param inputs - Class names to combine
|
|
82
|
+
* @returns Merged class string
|
|
83
|
+
*/
|
|
84
|
+
export function cn(...inputs: any[]): string;
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* React hook for media query
|
|
88
|
+
* @param query - Media query string
|
|
89
|
+
* @returns Boolean indicating if query matches
|
|
90
|
+
*/
|
|
91
|
+
export function useMediaQuery(query: string): boolean;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* React hook for responsive breakpoints
|
|
95
|
+
* @returns Object with breakpoint states and active breakpoint
|
|
96
|
+
*/
|
|
97
|
+
export function useBreakpoints(): {
|
|
98
|
+
isXs: boolean;
|
|
99
|
+
isSm: boolean;
|
|
100
|
+
isMd: boolean;
|
|
101
|
+
isLg: boolean;
|
|
102
|
+
active: 'xs' | 'sm' | 'md' | 'lg';
|
|
103
|
+
};`
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
path: 'lib/vue/utils.d.ts',
|
|
107
|
+
content: `import type { Ref, ComputedRef } from 'vue';
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Combines class names with tailwind-merge
|
|
111
|
+
* @param inputs - Class names to combine
|
|
112
|
+
* @returns Merged class string
|
|
113
|
+
*/
|
|
114
|
+
export function cn(...inputs: any[]): string;
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Vue composition API hook for media query
|
|
118
|
+
* @param query - Media query string
|
|
119
|
+
* @returns Ref<boolean> indicating if query matches
|
|
120
|
+
*/
|
|
121
|
+
export function useMediaQuery(query: string): Ref<boolean>;
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Vue composition API hook for responsive breakpoints
|
|
125
|
+
* @returns Object with breakpoint states and active breakpoint
|
|
126
|
+
*/
|
|
127
|
+
export function useBreakpoints(): {
|
|
128
|
+
isXs: Ref<boolean>;
|
|
129
|
+
isSm: Ref<boolean>;
|
|
130
|
+
isMd: Ref<boolean>;
|
|
131
|
+
isLg: Ref<boolean>;
|
|
132
|
+
active: ComputedRef<'xs' | 'sm' | 'md' | 'lg'>;
|
|
133
|
+
};`
|
|
134
|
+
}
|
|
135
|
+
];
|
|
136
|
+
|
|
137
|
+
// Write individual type declaration files
|
|
138
|
+
typeDeclarations.forEach(({ path: filePath, content }) => {
|
|
139
|
+
const fullPath = path.join(distDir, filePath);
|
|
140
|
+
const dir = path.dirname(fullPath);
|
|
141
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
142
|
+
fs.writeFileSync(fullPath, content);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
// Files to bundle (exclude dynamic loaders)
|
|
146
|
+
const filesToBundle = [
|
|
147
|
+
// Core utilities (bundle these)
|
|
148
|
+
{ input: 'lib/core/api-client.js', output: 'lib/core/api-client.js' },
|
|
149
|
+
{ input: 'lib/core/token-processor.js', output: 'lib/core/token-processor.js' },
|
|
150
|
+
{ input: 'lib/core/errors.js', output: 'lib/core/errors.js' },
|
|
151
|
+
{ input: 'lib/core/constants.js', output: 'lib/core/constants.js' },
|
|
152
|
+
{ input: 'lib/core/component-downloader.js', output: 'lib/core/component-downloader.js' },
|
|
153
|
+
|
|
154
|
+
// React/Vue utilities
|
|
155
|
+
{ input: 'lib/react/utils.mjs', output: 'lib/react/utils.mjs', format: 'esm' },
|
|
156
|
+
{ input: 'lib/vue/utils.mjs', output: 'lib/vue/utils.mjs', format: 'esm' },
|
|
157
|
+
|
|
158
|
+
// Main files
|
|
159
|
+
{ input: 'ffdc.js', output: 'ffdc.js' },
|
|
160
|
+
{ input: 'runtime.js', output: 'runtime.js' },
|
|
161
|
+
// CLI will be handled separately to preserve shebang
|
|
162
|
+
{ input: 'next.js', output: 'next.js' },
|
|
163
|
+
{ input: 'vite.js', output: 'vite.js' },
|
|
164
|
+
{ input: 'vite.mjs', output: 'vite.mjs', format: 'esm' },
|
|
165
|
+
];
|
|
166
|
+
|
|
167
|
+
// Files to copy without bundling (dynamic loaders)
|
|
168
|
+
const filesToCopy = [
|
|
169
|
+
{ input: 'lib/core/config-loader.js', output: 'lib/config/config-loader.js' },
|
|
170
|
+
{ input: 'lib/core/cache-manager.js', output: 'lib/config/cache-manager.js' },
|
|
171
|
+
{ input: 'scripts/generate-icon-types.js', output: 'scripts/generate-icon-types.js' },
|
|
172
|
+
];
|
|
173
|
+
|
|
174
|
+
// Build each file
|
|
175
|
+
async function build() {
|
|
176
|
+
console.log('Building frontfriend-tailwind...');
|
|
177
|
+
|
|
178
|
+
// Bundle files
|
|
179
|
+
for (const file of filesToBundle) {
|
|
180
|
+
try {
|
|
181
|
+
console.log(`Bundling ${file.input}...`);
|
|
182
|
+
|
|
183
|
+
await esbuild.build({
|
|
184
|
+
entryPoints: [path.join(__dirname, '..', file.input)],
|
|
185
|
+
bundle: true, // Bundle but keep external dependencies external
|
|
186
|
+
minify: true,
|
|
187
|
+
sourcemap: true,
|
|
188
|
+
format: file.format || 'cjs',
|
|
189
|
+
platform: 'node',
|
|
190
|
+
target: 'node14',
|
|
191
|
+
outfile: path.join(distDir, file.output),
|
|
192
|
+
external: [
|
|
193
|
+
'tailwindcss',
|
|
194
|
+
'commander',
|
|
195
|
+
'dotenv',
|
|
196
|
+
'color',
|
|
197
|
+
'clsx',
|
|
198
|
+
'tailwind-merge',
|
|
199
|
+
'fs',
|
|
200
|
+
'path',
|
|
201
|
+
'crypto',
|
|
202
|
+
'child_process',
|
|
203
|
+
'url',
|
|
204
|
+
'http',
|
|
205
|
+
'https',
|
|
206
|
+
'../config/*',
|
|
207
|
+
'./lib/config/*',
|
|
208
|
+
'@frontfriend/tailwind',
|
|
209
|
+
'@radix-ui/*',
|
|
210
|
+
'react',
|
|
211
|
+
'vue',
|
|
212
|
+
'class-variance-authority',
|
|
213
|
+
'lucide-react'
|
|
214
|
+
],
|
|
215
|
+
});
|
|
216
|
+
} catch (error) {
|
|
217
|
+
console.error(`Error building ${file.input}:`, error);
|
|
218
|
+
process.exit(1);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Copy dynamic loader files
|
|
223
|
+
for (const file of filesToCopy) {
|
|
224
|
+
console.log(`Copying ${file.input}...`);
|
|
225
|
+
let content = fs.readFileSync(path.join(__dirname, '..', file.input), 'utf8');
|
|
226
|
+
|
|
227
|
+
// Update relative imports to point to correct locations
|
|
228
|
+
if (file.input.includes('cache-manager.js')) {
|
|
229
|
+
content = content
|
|
230
|
+
.replace("require('./constants')", "require('../core/constants')")
|
|
231
|
+
.replace("require('./errors')", "require('../core/errors')");
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (file.input.includes('config-loader.js')) {
|
|
235
|
+
// No changes needed for config-loader
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
fs.writeFileSync(path.join(distDir, file.output), content);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Special handling for CLI to preserve shebang
|
|
242
|
+
console.log('Building cli.js with shebang...');
|
|
243
|
+
const cliContent = fs.readFileSync(path.join(__dirname, '..', 'cli.js'), 'utf8');
|
|
244
|
+
const cliLines = cliContent.split('\n');
|
|
245
|
+
const shebang = cliLines[0];
|
|
246
|
+
const cliCodeContent = cliLines.slice(1).join('\n');
|
|
247
|
+
|
|
248
|
+
// Update require paths in CLI
|
|
249
|
+
const updatedCliContent = cliCodeContent
|
|
250
|
+
.replace("require('./lib/core/config-loader')", "require('./lib/config/config-loader')")
|
|
251
|
+
.replace("require('./lib/core/cache-manager')", "require('./lib/config/cache-manager')");
|
|
252
|
+
|
|
253
|
+
// Build CLI without shebang
|
|
254
|
+
await esbuild.build({
|
|
255
|
+
stdin: {
|
|
256
|
+
contents: updatedCliContent,
|
|
257
|
+
resolveDir: path.join(__dirname, '..'),
|
|
258
|
+
sourcefile: 'cli.js',
|
|
259
|
+
},
|
|
260
|
+
bundle: true,
|
|
261
|
+
minify: true,
|
|
262
|
+
sourcemap: true,
|
|
263
|
+
format: 'cjs',
|
|
264
|
+
platform: 'node',
|
|
265
|
+
target: 'node14',
|
|
266
|
+
outfile: path.join(distDir, 'cli-temp.js'),
|
|
267
|
+
external: [
|
|
268
|
+
'commander',
|
|
269
|
+
'dotenv',
|
|
270
|
+
'fs',
|
|
271
|
+
'path',
|
|
272
|
+
'child_process',
|
|
273
|
+
'./lib/config/config-loader',
|
|
274
|
+
'./lib/config/cache-manager',
|
|
275
|
+
'./lib/core/api-client',
|
|
276
|
+
'./lib/core/component-downloader',
|
|
277
|
+
'./lib/core/token-processor',
|
|
278
|
+
'./lib/core/errors'
|
|
279
|
+
],
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
// Add shebang back and make executable
|
|
283
|
+
const builtCliContent = fs.readFileSync(path.join(distDir, 'cli-temp.js'), 'utf8');
|
|
284
|
+
fs.writeFileSync(path.join(distDir, 'cli.js'), shebang + '\n' + builtCliContent);
|
|
285
|
+
fs.unlinkSync(path.join(distDir, 'cli-temp.js'));
|
|
286
|
+
// Remove the temp map file if it exists
|
|
287
|
+
if (fs.existsSync(path.join(distDir, 'cli-temp.js.map'))) {
|
|
288
|
+
fs.unlinkSync(path.join(distDir, 'cli-temp.js.map'));
|
|
289
|
+
}
|
|
290
|
+
fs.chmodSync(path.join(distDir, 'cli.js'), '755');
|
|
291
|
+
|
|
292
|
+
// Special handling for index.js and index.mjs (need to update require paths)
|
|
293
|
+
console.log('Building index.js with updated paths...');
|
|
294
|
+
|
|
295
|
+
// Read original index.js
|
|
296
|
+
let indexContent = fs.readFileSync(path.join(__dirname, '..', 'index.js'), 'utf8');
|
|
297
|
+
|
|
298
|
+
// Update require paths for cache-manager
|
|
299
|
+
indexContent = indexContent.replace(
|
|
300
|
+
"require('./lib/core/cache-manager')",
|
|
301
|
+
"require('./lib/config/cache-manager')"
|
|
302
|
+
);
|
|
303
|
+
|
|
304
|
+
// Build CommonJS version
|
|
305
|
+
await esbuild.build({
|
|
306
|
+
stdin: {
|
|
307
|
+
contents: indexContent,
|
|
308
|
+
resolveDir: path.join(__dirname, '..'),
|
|
309
|
+
sourcefile: 'index.js',
|
|
310
|
+
},
|
|
311
|
+
bundle: true,
|
|
312
|
+
minify: true,
|
|
313
|
+
sourcemap: true,
|
|
314
|
+
format: 'cjs',
|
|
315
|
+
platform: 'node',
|
|
316
|
+
target: 'node14',
|
|
317
|
+
outfile: path.join(distDir, 'index.js'),
|
|
318
|
+
external: [
|
|
319
|
+
'tailwindcss',
|
|
320
|
+
'./lib/config/cache-manager',
|
|
321
|
+
'./ffdc',
|
|
322
|
+
'fs',
|
|
323
|
+
'path'
|
|
324
|
+
],
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
// Build ESM version
|
|
328
|
+
console.log('Building index.mjs...');
|
|
329
|
+
let indexMjsContent = fs.readFileSync(path.join(__dirname, '..', 'index.mjs'), 'utf8');
|
|
330
|
+
|
|
331
|
+
// Update import paths
|
|
332
|
+
indexMjsContent = indexMjsContent.replace(
|
|
333
|
+
"from './lib/core/cache-manager'",
|
|
334
|
+
"from './lib/config/cache-manager.js'"
|
|
335
|
+
);
|
|
336
|
+
|
|
337
|
+
await esbuild.build({
|
|
338
|
+
stdin: {
|
|
339
|
+
contents: indexMjsContent,
|
|
340
|
+
resolveDir: path.join(__dirname, '..'),
|
|
341
|
+
sourcefile: 'index.mjs',
|
|
342
|
+
},
|
|
343
|
+
bundle: true,
|
|
344
|
+
minify: true,
|
|
345
|
+
sourcemap: true,
|
|
346
|
+
format: 'esm',
|
|
347
|
+
platform: 'node',
|
|
348
|
+
target: 'node14',
|
|
349
|
+
outfile: path.join(distDir, 'index.mjs'),
|
|
350
|
+
external: [
|
|
351
|
+
'tailwindcss',
|
|
352
|
+
'./lib/config/cache-manager.js',
|
|
353
|
+
'./ffdc.js',
|
|
354
|
+
'fs',
|
|
355
|
+
'path'
|
|
356
|
+
],
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
console.log('Build completed successfully!');
|
|
360
|
+
|
|
361
|
+
// Show dist structure
|
|
362
|
+
console.log('\nDist structure:');
|
|
363
|
+
const files = await glob('**/*', { cwd: distDir });
|
|
364
|
+
files.forEach(file => console.log(` dist/${file}`));
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// Run build
|
|
368
|
+
build().catch(error => {
|
|
369
|
+
console.error('Build failed:', error);
|
|
370
|
+
process.exit(1);
|
|
371
|
+
});
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Generate TypeScript types from icons.json cache file
|
|
8
|
+
* This script reads the icons.json file and generates proper types for the iconSet
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
function generateIconTypes() {
|
|
12
|
+
const projectRoot = process.cwd();
|
|
13
|
+
const iconsPath = path.join(projectRoot, 'node_modules', '.cache', 'frontfriend', 'icons.json');
|
|
14
|
+
const outputPath = path.join(projectRoot, 'types', 'frontfriend-icons.d.ts');
|
|
15
|
+
|
|
16
|
+
// Check if icons.json exists
|
|
17
|
+
if (!fs.existsSync(iconsPath)) {
|
|
18
|
+
console.error('[FrontFriend] Error: icons.json not found. Please run "npx frontfriend setup" first.');
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
// Read icons.json
|
|
24
|
+
const icons = JSON.parse(fs.readFileSync(iconsPath, 'utf-8'));
|
|
25
|
+
|
|
26
|
+
// Extract all unique icon names
|
|
27
|
+
const iconNames = new Set();
|
|
28
|
+
|
|
29
|
+
function extractIconNames(obj) {
|
|
30
|
+
for (const value of Object.values(obj)) {
|
|
31
|
+
if (typeof value === 'string') {
|
|
32
|
+
iconNames.add(value);
|
|
33
|
+
} else if (typeof value === 'object' && value !== null) {
|
|
34
|
+
extractIconNames(value);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
extractIconNames(icons);
|
|
40
|
+
|
|
41
|
+
// Generate the interface structure recursively
|
|
42
|
+
function generateInterface(obj, indent = ' ') {
|
|
43
|
+
const lines = [];
|
|
44
|
+
|
|
45
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
46
|
+
if (typeof value === 'string') {
|
|
47
|
+
lines.push(`${indent}${key}: '${value}';`);
|
|
48
|
+
} else if (typeof value === 'object' && value !== null) {
|
|
49
|
+
lines.push(`${indent}${key}: {`);
|
|
50
|
+
lines.push(generateInterface(value, indent + ' '));
|
|
51
|
+
lines.push(`${indent}};`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return lines.join('\n');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Generate the type definition file
|
|
59
|
+
const iconNameType = Array.from(iconNames).map(name => `'${name}'`).join(' | ');
|
|
60
|
+
|
|
61
|
+
const typeDefinition = `// Generated by @frontfriend/tailwind
|
|
62
|
+
// DO NOT EDIT THIS FILE MANUALLY
|
|
63
|
+
|
|
64
|
+
import type { IconSetStructure } from '@frontfriend/tailwind';
|
|
65
|
+
|
|
66
|
+
declare module '@frontfriend/tailwind' {
|
|
67
|
+
// Icon names used in this project
|
|
68
|
+
export type ProjectIconName = ${iconNameType || 'string'};
|
|
69
|
+
|
|
70
|
+
// Typed iconSet structure with exact icon names
|
|
71
|
+
export interface TypedIconSet extends IconSetStructure {
|
|
72
|
+
${generateInterface(icons)}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Override the iconSet type with the typed version
|
|
76
|
+
export const iconSet: TypedIconSet;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Augment Vue component types with exact icon names
|
|
80
|
+
declare module '*/components/ui/icon/*.vue' {
|
|
81
|
+
export type IconName = ${iconNameType || 'string'};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
declare module '@/components/ui/icon/*.vue' {
|
|
85
|
+
export type IconName = ${iconNameType || 'string'};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
declare module '@/components/ui/icon' {
|
|
89
|
+
export type IconName = ${iconNameType || 'string'};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
declare module '@/src/components/ui/icon' {
|
|
93
|
+
export type IconName = ${iconNameType || 'string'};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
declare module '@/src/components/ui/icon/Icon.vue' {
|
|
97
|
+
export type IconName = ${iconNameType || 'string'};
|
|
98
|
+
}
|
|
99
|
+
`;
|
|
100
|
+
|
|
101
|
+
// Ensure types directory exists
|
|
102
|
+
const typesDir = path.dirname(outputPath);
|
|
103
|
+
if (!fs.existsSync(typesDir)) {
|
|
104
|
+
fs.mkdirSync(typesDir, { recursive: true });
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Write the type definition file
|
|
108
|
+
fs.writeFileSync(outputPath, typeDefinition);
|
|
109
|
+
|
|
110
|
+
console.log('[FrontFriend] ✓ Generated icon types at types/frontfriend-icons.d.ts');
|
|
111
|
+
|
|
112
|
+
// Check if tsconfig.json exists and update it
|
|
113
|
+
const tsconfigPath = path.join(projectRoot, 'tsconfig.json');
|
|
114
|
+
if (fs.existsSync(tsconfigPath)) {
|
|
115
|
+
const tsconfig = JSON.parse(fs.readFileSync(tsconfigPath, 'utf-8'));
|
|
116
|
+
|
|
117
|
+
// Ensure the types file is included
|
|
118
|
+
if (!tsconfig.include) {
|
|
119
|
+
tsconfig.include = [];
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const typesPattern = 'types/**/*.d.ts';
|
|
123
|
+
if (!tsconfig.include.includes(typesPattern)) {
|
|
124
|
+
tsconfig.include.push(typesPattern);
|
|
125
|
+
fs.writeFileSync(tsconfigPath, JSON.stringify(tsconfig, null, 2));
|
|
126
|
+
console.log('[FrontFriend] ✓ Updated tsconfig.json to include generated types');
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
} catch (error) {
|
|
131
|
+
console.error('[FrontFriend] Error generating icon types:', error.message);
|
|
132
|
+
process.exit(1);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Run if called directly
|
|
137
|
+
if (require.main === module) {
|
|
138
|
+
generateIconTypes();
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
module.exports = { generateIconTypes };
|