Setting the file. One moment.
Generate Visual Assets · Wix Headless Replatform · wix/skills · Skills Docs
ContentsBack to the top of the page 28.10
Workflow
Next
Script Browser Tooling
scripts/ generate-visual-assets.mjs
JavaScript · 111 lines · 6 KB
0
]
||
args.url, args.out);
9 const contract = await generateVisualAssets ({ outputDir });
10 if (args.json) process.stdout. write ( `${ JSON . stringify ( contract , null , 2 ) } \n ` );
11 }
12
13 export async function generateVisualAssets ({ outputDir , pages : suppliedPages , assets : suppliedAssets } = {}) {
14 const docs = docsDir (outputDir);
15 const sourceMap = suppliedPages ? null : await readJson (path. join (docs, "source-map.json" ));
16 const pages = suppliedPages || sourceMap?.pages || [];
17 let assets = suppliedAssets;
18 if ( ! assets) {
19 try { assets = await readJson (path. join (docs, "assets.json" )); } catch { assets = { assets: [] }; }
20 }
21 const downloaded = new Map ((assets?.assets || assets || []). map (( asset ) => [asset.sourceUrl || asset.url || "" , asset.localPath || asset.path || "" ]));
22 const groups = new Map ();
23 for ( const page of pages) {
24 for ( const record of page.visualAssets || []) {
25 if ( /cookielaw | onetrust | ot-sdk | cookiebot | quantcast/ i . test ( `${ record . sourceUrl || ""} ${ record . useHref || ""} ${ record . domRef ?. id || ""} ${ ( record . domRef ?. classTokens || []). join ( " " ) }` )) continue ;
26 const sourceIdentity = record.sourceUrl || record.useHref || record.symbolMarkup || record.svgMarkup || `${ record . domRef ?. id }:${ record . domRef ?. classTokens ?. join ( "." ) }` ;
27 const key = `${ record . kind } \u0000 ${ record . sourceType } \u0000 ${ sourceIdentity }` ;
28 const group = groups. get (key) || {
29 id: "" ,
30 kind: record.kind,
31 sourceType: record.sourceType,
32 sourceUrl: record.sourceUrl || "" ,
33 useHref: record.useHref || "" ,
34 accessibleName: record.accessibleName || "" ,
35 sourceMarkup: record.svgMarkup || "" ,
36 symbolMarkup: record.symbolMarkup || "" ,
37 localPath: downloaded. get (record.sourceUrl) || "" ,
38 usages: [],
39 };
40 group.usages. push ({
41 pageUrl: page.url,
42 context: record.context,
43 variant: record.variant,
44 renderedSize: record.renderedSize,
45 intrinsicSize: record.intrinsicSize,
46 presentation: record.presentation,
47 visible: record.visible,
48 });
49 groups. set (key, group);
50 }
51 }
52 const entries = Array. from (groups. values ());
53 const publicDir = path. join (outputDir, "public" , "site-clone" , "visual-assets" );
54 await rm (publicDir, { recursive: true , force: true });
55 await ensureDir (publicDir);
56 for ( const [ index , entry ] of entries. entries ()) {
57 entry.id = `${ entry . kind }-${ String ( index + 1 ). padStart ( 3 , "0" ) }` ;
58 if ( ! [ "inline-svg" , "svg-sprite-use" ]. includes (entry.sourceType)) continue ;
59 const svg = standaloneSvg (entry);
60 if ( ! svg) continue ;
61 const hint = kebab (entry.accessibleName || entry.useHref || entry.usages[ 0 ]?.variant || entry.id). slice ( 0 , 60 );
62 const filename = `${ entry . id }-${ hint || "source"}.svg` ;
63 await writeText (path. join (publicDir, filename), svg);
64 entry.localPath = `/site-clone/visual-assets/${ filename }` ;
65 entry.materializedFromSource = true ;
66 }
67 const contract = {
68 schemaVersion: 1 ,
69 generatedAt: new Date (). toISOString (),
70 sourceUrl: pages[ 0 ]?.url || sourceMap?.sourceUrl || "" ,
71 logos: entries. filter (( entry ) => entry.kind === "logo" ),
72 icons: entries. filter (( entry ) => entry.kind === "icon" ),
73 policy: {
74 logo: [ "exact-source-file-or-materialized-svg" , "all-observed-variants-and-usage-sizes-required" , "never-recreate-as-text" , "never-substitute-library-icon" ],
75 icon: [ "exact-source-svg-or-image" , "source-sprite-or-source-library" , "style-matched-established-library-fallback" ],
76 fallbackLibrary: "Iconify or another established library whose family matches the captured stroke/fill style; only when no source icon is available." ,
77 },
78 };
79 await writeJson (path. join (docs, "visual-assets.json" ), contract);
80 await writeText (path. join (docs, "visual-assets.md" ), renderMarkdown (contract));
81 return contract;
82 }
83
84 function standaloneSvg ( entry ) {
85 if (entry.sourceType === "inline-svg" && / ^ <svg \b / i . test (entry.sourceMarkup. trim ())) {
86 return entry.sourceMarkup. includes ( "xmlns=" ) ? `${ entry . sourceMarkup . trim () } \n ` : entry.sourceMarkup. replace ( / ^ <svg \b / i , '<svg xmlns="http://www.w3.org/2000/svg"' );
87 }
88 const symbol = entry.symbolMarkup. trim ();
89 if ( ! symbol) return "" ;
90 const viewBox = symbol. match ( / \b viewBox= ["'] ( [ ^ "'] + ) ["'] / i )?.[ 1 ]
91 || entry.usages. find (( usage ) => usage.intrinsicSize?.viewBox)?.intrinsicSize.viewBox
92 || "0 0 100 100" ;
93 const symbolId = symbol. match ( / \b id= ["'] ( [ ^ "'] + ) ["'] / i )?.[ 1 ] || String (entry.useHref || "" ). replace ( / ^ #/ , "source-symbol" );
94 const presentation = entry.usages. find (( usage ) => usage.visible)?.presentation || entry.usages[ 0 ]?.presentation || {};
95 const style = `color:${ presentation . color || "currentColor"};fill:${ presentation . fill || "currentColor"};stroke:${ presentation . stroke || "none"}` ;
96 return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="${ escapeXml ( viewBox ) }" style="${ escapeXml ( style ) }"><defs>${ symbol }</defs><use href="#${ escapeXml ( symbolId ) }"/></svg> \n ` ;
97 }
98
99 function escapeXml ( value ) {
100 return String (value || "" ). replace ( /&/ g , "&" ). replace ( /"/ g , """ ). replace ( /</ g , "<" ). replace ( />/ g , ">" );
101 }
102
103 function renderMarkdown ( contract ) {
104 const render = ( entry ) => `- \` ${ entry . id } \` (${ entry . sourceType }): ${ entry . localPath || entry . sourceUrl || entry . useHref || "captured source markup"}; usages: ${ entry . usages . map (( usage ) => `${ usage . context }/${ usage . variant } ${ usage . renderedSize ?. width || 0 }×${ usage . renderedSize ?. height || 0 }` ). join ( ", " ) }` ;
105 return `# Visual Asset Contract \n\n ## Non-negotiable brand rules \n\n ${ contract . policy . logo . map (( item ) => `- ${ item }` ). join ( " \n " ) } \n\n ## Logos \n\n ${ contract . logos . map ( render ). join ( " \n " ) || "_No logo candidate captured; this is a blocking discovery warning and requires source inspection._"} \n\n ## Icons \n\n Source-first order: exact source → source library/sprite → style-matched established library fallback. \n\n ${ contract . icons . map ( render ). join ( " \n " ) || "_No standalone/source icon captured._"} \n ` ;
106 }
107
108 if ( import . meta .url === `file://${ process . argv [ 1 ] }` ) main (). catch (( error ) => {
109 console. error (error.stack || error.message);
110 process. exit ( 1 );
111 });