@solar-icons/codemod 2.0.0-beta.4 → 2.1.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.
package/README.md CHANGED
@@ -7,18 +7,18 @@ Conservative, opt-in migrations for Solar Icons v2.
7
7
  Use the interactive assistant when running the migration by hand. It detects supported frameworks, asks for the React and Vue strategy when relevant, and requires confirmation before it writes files.
8
8
 
9
9
  ```bash
10
- npx @solar-icons/codemod@beta --interactive
10
+ npx @solar-icons/codemod --interactive
11
11
  ```
12
12
 
13
13
  Use arguments for scripts, CI, or repeatable migrations. The command previews changes unless `--write` is passed.
14
14
 
15
15
  ```bash
16
- npx @solar-icons/codemod@beta --react-v1-mode static
17
- npx @solar-icons/codemod@beta ./apps/web --react-v1-mode static --write
18
- npx @solar-icons/codemod@beta --json > solar-icons-migration.json
16
+ npx @solar-icons/codemod --react-v1-mode static
17
+ npx @solar-icons/codemod ./apps/web --react-v1-mode static --write
18
+ npx @solar-icons/codemod --json > solar-icons-migration.json
19
19
  ```
20
20
 
21
- Run `npx @solar-icons/codemod@beta --help` for every option. `--cwd <path>` remains available for existing scripts, but a directory argument is shorter.
21
+ Run `npx @solar-icons/codemod --help` for every option. `--cwd <path>` remains available for existing scripts, but a directory argument is shorter.
22
22
 
23
23
  ## React v1 strategy
24
24
 
@@ -48,7 +48,7 @@ The Angular adapter renames static icon exports to their `Solar`-prefixed v2 nam
48
48
 
49
49
  The codemod reports, without rewriting, legacy providers and `useSolar`, category imports, default namespace imports, and removed `mirrored` props. These need an application-level decision and are linked to the v2 migration guide.
50
50
 
51
- All 37 removed icon names are converted through an explicit v1-to-v2 mapping.
51
+ All 37 removed icon names are converted through an explicit v1-to-v2 mapping. The codemod also normalizes the six current catalogue aliases introduced by the file and chat naming cleanup (`code-file`, `cloud-file`, `figma-file`, `chat-dots`, `chat-line`, and `chat-unread`) to their canonical names while those old names remain available as deprecated compatibility exports.
52
52
 
53
53
  ## Verification
54
54
 
package/dist/cli.mjs CHANGED
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- import{detectFrameworks as e}from"./detect.mjs";import{transformPackageJson as t}from"./package-json.mjs";import{collectAngularSelectorRenames as n,transformAngular as r,transformAngularTemplate as i}from"./transforms/angular.mjs";import{transformNuxt as a}from"./transforms/nuxt.mjs";import{transformReactNative as o}from"./transforms/react-native.mjs";import{transformReactPerf as s}from"./transforms/react-perf.mjs";import{transformReact as c}from"./transforms/react.mjs";import{transformSolid as l}from"./transforms/solid.mjs";import{transformSvelte as u}from"./transforms/svelte.mjs";import{transformVue as d}from"./transforms/vue.mjs";import{readFile as f,readdir as p,writeFile as m}from"node:fs/promises";import{extname as h,join as g,resolve as _}from"node:path";import{realpathSync as v}from"node:fs";import{pathToFileURL as y}from"node:url";import*as b from"@clack/prompts";import{Command as x,InvalidArgumentError as S}from"commander";import C from"picocolors";const w=new Set([`.html`,`.js`,`.jsx`,`.mjs`,`.ts`,`.tsx`,`.svelte`,`.vue`]),T=new Set([`.git`,`.next`,`.nuxt`,`.svelte-kit`,`coverage`,`dist`,`node_modules`]);async function E(e){let t=await p(e,{withFileTypes:!0});return(await Promise.all(t.map(async t=>{let n=g(e,t.name);return t.isDirectory()?T.has(t.name)?[]:E(n):t.isFile()&&w.has(h(t.name))?[n]:[]}))).flat()}async function D({cwd:p,reactV1Mode:h=`static`,targetVersion:_,vueV1Mode:v=`static`,write:y=!1}){let b=await e(p),x=await E(p),S=new Map(await Promise.all(x.map(async e=>[e,await f(e,`utf8`)]))),C=new Map;for(let[e,t]of S)for(let[r,i]of n(t,e))C.set(r,i);let w=new Set(x),T=[],D=[];for(let e of x){let t=s(S.get(e),e),n=c(t.code,e,h),f=o(n.code,e),p=d(f.code,e,v),g=a(p.code,e),_=u(g.code,e),b=l(_.code,e),x=r(b.code,e,w),E=i(x.code,C);D.push(...t.diagnostics,...n.diagnostics,...f.diagnostics,...p.diagnostics,...g.diagnostics,..._.diagnostics,...b.diagnostics,...x.diagnostics,...E.diagnostics),!(!t.changed&&!n.changed&&!f.changed&&!p.changed&&!g.changed&&!_.changed&&!b.changed&&!x.changed&&!E.changed)&&(T.push(e),y&&await m(e,E.code))}let O=g(p,`package.json`),k=t(await f(O,`utf8`),_);return k.changed&&(T.push(O),y&&await m(O,k.code)),{changedFiles:T,diagnostics:D,detectedFrameworks:b}}function O(e){if(e===`static`||e===`dynamic`)return e;throw new S(`Expected either "static" or "dynamic".`)}function k(e){let t=e.file&&e.line?`${e.file}:${e.line}:${e.column??1}`:e.file,n=e.severity===`error`?C.red(`error`):C.yellow(`warning`);return`${C.dim(t??`solar-icons`)} ${n} ${C.bold(`[${e.code}]`)} ${e.message}`}function A(e,t){console.info(`${C.cyan(`Detected frameworks:`)} ${e.detectedFrameworks.join(`, `)||`none`}`),console.info(`${t?C.green(`Migrated`):C.cyan(`Would migrate`)} ${C.bold(String(e.changedFiles.length))} file(s).`);for(let t of e.diagnostics)console.warn(k(t));!t&&e.changedFiles.length>0&&console.info(C.dim(`Run again with --write to apply these changes.`))}async function j(e){let t=await b.select({message:`${e} migration strategy`,options:[{value:`static`,label:`Static (recommended)`,hint:`one style per import and the smallest bundle`},{value:`dynamic`,label:`Dynamic`,hint:`preserve runtime style switching`}]});if(!b.isCancel(t))return t}async function M(t){b.intro(C.bgCyan(C.black(` Solar Icons v2 migration `)));let n=await e(t);b.log.info(`Detected: ${n.join(`, `)||`no supported framework`}`);let r=n.includes(`react`)?await j(`React`):void 0;if(n.includes(`react`)&&!r){b.cancel(`Migration cancelled.`);return}let i=n.includes(`vue`)?await j(`Vue`):void 0;if(n.includes(`vue`)&&!i){b.cancel(`Migration cancelled.`);return}let a=await b.select({message:`Choose an action`,options:[{value:`preview`,label:`Preview changes`,hint:`does not modify files`},{value:`write`,label:`Apply changes`,hint:`writes the migration to disk`}]});if(b.isCancel(a)){b.cancel(`Migration cancelled.`);return}let o=a===`write`;if(o){let e=await b.confirm({message:`Write the migration to this project?`,initialValue:!1});if(b.isCancel(e)||!e){b.cancel(`Migration cancelled.`);return}}return{reactV1Mode:r,vueV1Mode:i,write:o}}async function N(){let e=new x().name(`solar-icons-migrate`).description(`Migrate a Solar Icons project from the pre-v2 API to v2.`).argument(`[directory]`,`project directory, defaults to the current directory`).option(`-C, --cwd <path>`,`project directory, kept for backwards compatibility`).option(`-i, --interactive`,`guide the migration with prompts`).option(`-w, --write`,`apply changes instead of previewing them`).option(`--react-v1-mode <mode>`,`React strategy: static or dynamic`,O).option(`--vue-v1-mode <mode>`,`Vue strategy: static or dynamic`,O).option(`--target-version <version>`,`Solar Icons v2 version to add to package.json`).option(`--json`,`write a machine-readable report to stdout`).showHelpAfterError().showSuggestionAfterError();e.action(async(t,n)=>{t&&n.cwd&&e.error(`Use either [directory] or --cwd, not both.`,{exitCode:2}),n.interactive&&n.json&&e.error(`--interactive cannot be combined with --json.`,{exitCode:2});let r=_(n.cwd??t??process.cwd()),i=n.interactive?await M(r):void 0;if(n.interactive&&!i)return;let a={cwd:r,reactV1Mode:i?.reactV1Mode??n.reactV1Mode,targetVersion:n.targetVersion,vueV1Mode:i?.vueV1Mode??n.vueV1Mode,write:i?.write??n.write},o=await D(a);n.json?console.info(JSON.stringify(o,null,2)):A(o,!!a.write),n.interactive&&b.outro(`Migration complete.`)}),await e.parseAsync()}const P=process.argv[1]?v(process.argv[1]):void 0;P&&import.meta.url===y(P).href&&N();export{D as runMigration};
2
+ import{detectFrameworks as e}from"./detect.mjs";import{transformPackageJson as t}from"./package-json.mjs";import{collectAngularSelectorRenames as n,transformAngular as r,transformAngularTemplate as i}from"./transforms/angular.mjs";import{transformNuxt as a}from"./transforms/nuxt.mjs";import{transformReactNative as o}from"./transforms/react-native.mjs";import{transformReactPerf as s}from"./transforms/react-perf.mjs";import{transformReact as c}from"./transforms/react.mjs";import{transformSolid as l}from"./transforms/solid.mjs";import{transformSvelte as u}from"./transforms/svelte.mjs";import{transformVue as d}from"./transforms/vue.mjs";import{readFile as f,readdir as p,writeFile as m}from"node:fs/promises";import{extname as h,join as g,resolve as _}from"node:path";import{realpathSync as v}from"node:fs";import{pathToFileURL as y}from"node:url";import*as b from"@clack/prompts";import{Command as x,InvalidArgumentError as S}from"commander";import C from"picocolors";const w=new Set([`.html`,`.js`,`.jsx`,`.mjs`,`.ts`,`.tsx`,`.svelte`,`.vue`]),T=new Set([`.git`,`.next`,`.nuxt`,`.svelte-kit`,`coverage`,`dist`,`node_modules`]);async function E(e){let t=await p(e,{withFileTypes:!0});return(await Promise.all(t.map(async t=>{let n=g(e,t.name);return t.isDirectory()?T.has(t.name)?[]:E(n):t.isFile()&&w.has(h(t.name))?[n]:[]}))).flat()}async function D({cwd:p,reactV1Mode:h=`static`,targetVersion:_,vueV1Mode:v=`static`,write:y=!1}){let b=await e(p),x=await E(p),S=new Map(await Promise.all(x.map(async e=>[e,await f(e,`utf8`)]))),C=new Map;for(let[e,t]of S)for(let[r,i]of n(t,e))C.set(r,i);let w=new Set(x),T=[],D=[];for(let e of x){let t=S.get(e),n=s(t,e),f=c(n.code,e,h),p=o(f.code,e),g=d(p.code,e,v),_=a(g.code,e),b=u(_.code,e),x=l(b.code,e),E=r(x.code,e,w),O=i(E.code,C);D.push(...n.diagnostics,...f.diagnostics,...p.diagnostics,...g.diagnostics,..._.diagnostics,...b.diagnostics,...x.diagnostics,...E.diagnostics,...O.diagnostics),(n.changed||f.changed||p.changed||g.changed||_.changed||b.changed||x.changed||E.changed||O.changed)&&(T.push(e),y&&await m(e,O.code))}let O=g(p,`package.json`),k=t(await f(O,`utf8`),_);return k.changed&&(T.push(O),y&&await m(O,k.code)),{changedFiles:T,diagnostics:D,detectedFrameworks:b}}function O(e){if(e===`static`||e===`dynamic`)return e;throw new S(`Expected either "static" or "dynamic".`)}function k(e){let t=e.file&&e.line?`${e.file}:${e.line}:${e.column??1}`:e.file,n=e.severity===`error`?C.red(`error`):C.yellow(`warning`);return`${C.dim(t??`solar-icons`)} ${n} ${C.bold(`[${e.code}]`)} ${e.message}`}function A(e,t){console.info(`${C.cyan(`Detected frameworks:`)} ${e.detectedFrameworks.join(`, `)||`none`}`),console.info(`${t?C.green(`Migrated`):C.cyan(`Would migrate`)} ${C.bold(String(e.changedFiles.length))} file(s).`);for(let t of e.diagnostics)console.warn(k(t));!t&&e.changedFiles.length>0&&console.info(C.dim(`Run again with --write to apply these changes.`))}async function j(e){let t=await b.select({message:`${e} migration strategy`,options:[{value:`static`,label:`Static (recommended)`,hint:`one style per import and the smallest bundle`},{value:`dynamic`,label:`Dynamic`,hint:`preserve runtime style switching`}]});if(!b.isCancel(t))return t}async function M(t){b.intro(C.bgCyan(C.black(` Solar Icons v2 migration `)));let n=await e(t);b.log.info(`Detected: ${n.join(`, `)||`no supported framework`}`);let r=n.includes(`react`)?await j(`React`):void 0;if(n.includes(`react`)&&!r){b.cancel(`Migration cancelled.`);return}let i=n.includes(`vue`)?await j(`Vue`):void 0;if(n.includes(`vue`)&&!i){b.cancel(`Migration cancelled.`);return}let a=await b.select({message:`Choose an action`,options:[{value:`preview`,label:`Preview changes`,hint:`does not modify files`},{value:`write`,label:`Apply changes`,hint:`writes the migration to disk`}]});if(b.isCancel(a)){b.cancel(`Migration cancelled.`);return}let o=a===`write`;if(o){let e=await b.confirm({message:`Write the migration to this project?`,initialValue:!1});if(b.isCancel(e)||!e){b.cancel(`Migration cancelled.`);return}}return{reactV1Mode:r,vueV1Mode:i,write:o}}async function N(){let e=new x().name(`solar-icons-migrate`).description(`Migrate a Solar Icons project from the pre-v2 API to v2.`).argument(`[directory]`,`project directory, defaults to the current directory`).option(`-C, --cwd <path>`,`project directory, kept for backwards compatibility`).option(`-i, --interactive`,`guide the migration with prompts`).option(`-w, --write`,`apply changes instead of previewing them`).option(`--react-v1-mode <mode>`,`React strategy: static or dynamic`,O).option(`--vue-v1-mode <mode>`,`Vue strategy: static or dynamic`,O).option(`--target-version <version>`,`Solar Icons v2 version to add to package.json`).option(`--json`,`write a machine-readable report to stdout`).showHelpAfterError().showSuggestionAfterError();e.action(async(t,n)=>{t&&n.cwd&&e.error(`Use either [directory] or --cwd, not both.`,{exitCode:2}),n.interactive&&n.json&&e.error(`--interactive cannot be combined with --json.`,{exitCode:2});let r=_(n.cwd??t??process.cwd()),i=n.interactive?await M(r):void 0;if(n.interactive&&!i)return;let a={cwd:r,reactV1Mode:i?.reactV1Mode??n.reactV1Mode,targetVersion:n.targetVersion,vueV1Mode:i?.vueV1Mode??n.vueV1Mode,write:i?.write??n.write},o=await D(a);n.json?console.info(JSON.stringify(o,null,2)):A(o,!!a.write),n.interactive&&b.outro(`Migration complete.`)}),await e.parseAsync()}const P=process.argv[1]?v(process.argv[1]):void 0;P&&import.meta.url===y(P).href&&N();export{D as runMigration};
@@ -1,5 +1,5 @@
1
1
  //#region src/icon-renames.d.ts
2
- /** Complete v1-to-v2 icon rename table. Old exports do not exist in v2. */
2
+ /** Complete v1-to-v2 breaking rename table. */
3
3
  declare const iconRenames: Record<string, string>;
4
4
  declare function renameIcon(name: string): string;
5
5
  //#endregion
@@ -1 +1 @@
1
- const e={Accumulator:`CarBattery`,BellBing:`BellRing`,BoneBroken:`BoneFracture`,Clound:`Cloud`,Condicioner:`Conditioner`,Essentional:`Essential`,FileFavourite:`FileFavorite`,FolderFavouriteBookmark:`FolderFavoriteBookmark`,FolderFavouriteStar:`FolderFavoriteStar`,GalleryFavourite:`GalleryFavorite`,Globus:`Globe`,Happly:`Happy`,HeartBroken:`HeartCrack`,Horizontall:`Horizontal`,Infinity:`Infinite`,LinkBroken:`Unlink`,LinkBrokenMinimalistic:`UnlinkMinimalistic`,MagicStick:`MagicWand`,MagicStick2:`MagicWand2`,MagicStick3:`MagicWand3`,Magnifer:`Magnifier`,MapPointFavourite:`MapPointFavorite`,Minimlistic:`Minimalistic`,Pallete:`Palette`,Plain:`Plane`,Plain2:`Plane2`,Plain3:`Plane3`,Plaaylist:`Playlist`,Recive:`Receive`,Siderbar:`Sidebar`,SortByAlphabet:`SortAlphabetically`,Spedometer:`Speedometer`,Text:`TextFormat`,Trellis:`Vanity`,Tuneing:`Tuning`,WadOfMoney:`MoneyRoll`,Weigher:`Scale`},t={Clound:`Cloud`,Condicioner:`Conditioner`,Essentional:`Essential`,Happly:`Happy`,Magnifer:`Magnifier`,Minimlistic:`Minimalistic`,Pallete:`Palette`,Plaaylist:`Playlist`,Recive:`Receive`,Siderbar:`Sidebar`,Spedometer:`Speedometer`,Tuneing:`Tuning`};function n(n){return e[n]?e[n]:Object.entries(t).reduce((e,[t,n])=>e.replaceAll(t,n),n)}export{e as iconRenames,n as renameIcon};
1
+ const e={Accumulator:`CarBattery`,BellBing:`BellRing`,BoneBroken:`BoneFracture`,Clound:`Cloud`,Condicioner:`Conditioner`,Essentional:`Essential`,FileFavourite:`FileFavorite`,FolderFavouriteBookmark:`FolderFavoriteBookmark`,FolderFavouriteStar:`FolderFavoriteStar`,GalleryFavourite:`GalleryFavorite`,Globus:`Globe`,Happly:`Happy`,HeartBroken:`HeartCrack`,Horizontall:`Horizontal`,Infinity:`Infinite`,LinkBroken:`Unlink`,LinkBrokenMinimalistic:`UnlinkMinimalistic`,MagicStick:`MagicWand`,MagicStick2:`MagicWand2`,MagicStick3:`MagicWand3`,Magnifer:`Magnifier`,MapPointFavourite:`MapPointFavorite`,Minimlistic:`Minimalistic`,Pallete:`Palette`,Plain:`Plane`,Plain2:`Plane2`,Plain3:`Plane3`,Plaaylist:`Playlist`,Recive:`Receive`,Siderbar:`Sidebar`,SortByAlphabet:`SortAlphabetically`,Spedometer:`Speedometer`,Text:`TextFormat`,Trellis:`Vanity`,Tuneing:`Tuning`,WadOfMoney:`MoneyRoll`,Weigher:`Scale`},t={ChatDots:`ChatSquareDots`,ChatLine:`ChatSquareLine`,ChatUnread:`ChatSquareUnread`,CloudFile:`FileCloud`,CodeFile:`FileCode`,FigmaFile:`FileFigma`},n={Clound:`Cloud`,Condicioner:`Conditioner`,Essentional:`Essential`,Happly:`Happy`,Magnifer:`Magnifier`,Minimlistic:`Minimalistic`,Pallete:`Palette`,Plaaylist:`Playlist`,Recive:`Receive`,Siderbar:`Sidebar`,Spedometer:`Speedometer`,Tuneing:`Tuning`};function r(r){if(e[r])return e[r];if(t[r])return t[r];let i=Object.entries(n).reduce((e,[t,n])=>e.replaceAll(t,n),r);return Object.entries(t).reduce((e,[t,n])=>e.replaceAll(t,n),i)}export{e as iconRenames,r as renameIcon};
@@ -1 +1 @@
1
- import e from"typescript";function t(t,n,r){if(r.size===0)return[];let i={allowJs:!0,jsx:e.JsxEmit.ReactJSX,noResolve:!0,target:e.ScriptTarget.Latest},a=e.createSourceFile(n,t,e.ScriptTarget.Latest,!0),o=e.createCompilerHost(i),s=o.getSourceFile.bind(o);o.getSourceFile=(e,t,r,i)=>e===n?a:s(e,t,r,i);let c=e.createProgram([n],i,o),l=c.getSourceFile(n);if(!l)return[];let u=c.getTypeChecker(),d=new Map;for(let t of l.statements){if(!e.isImportDeclaration(t))continue;let n=t.importClause?.namedBindings;if(!(!n||!e.isNamedImports(n)))for(let e of n.elements){let t=e.name.text;if(!r.has(t))continue;let n=u.getSymbolAtLocation(e.name);n&&d.set(t,n)}}let f=[],p=t=>{if(e.isIdentifier(t)&&!e.isImportSpecifier(t.parent)){let e=r.get(t.text),n=d.get(t.text);e&&n&&u.getSymbolAtLocation(t)===n&&f.push({end:t.getEnd(),start:t.getStart(l),text:e})}e.forEachChild(t,p)};return e.forEachChild(l,p),f}export{t as renameImportedBindingReferences};
1
+ import e from"typescript";function t(t,n,r){if(r.size===0)return[];let i={allowJs:!0,jsx:e.JsxEmit.ReactJSX,noResolve:!0,target:e.ScriptTarget.Latest},a=e.createSourceFile(n,t,e.ScriptTarget.Latest,!0),o=e.createCompilerHost(i),s=o.getSourceFile.bind(o);o.getSourceFile=(e,t,r,i)=>e===n?a:s(e,t,r,i);let c=e.createProgram([n],i,o),l=c.getSourceFile(n);if(!l)return[];let u=c.getTypeChecker(),d=new Map;for(let t of l.statements){if(!e.isImportDeclaration(t))continue;let n=t.importClause?.namedBindings;if(n&&e.isNamedImports(n))for(let e of n.elements){let t=e.name.text;if(!r.has(t))continue;let n=u.getSymbolAtLocation(e.name);n&&d.set(t,n)}}let f=[],p=t=>{if(e.isIdentifier(t)&&!e.isImportSpecifier(t.parent)){let e=r.get(t.text),n=d.get(t.text);e&&n&&u.getSymbolAtLocation(t)===n&&f.push({end:t.getEnd(),start:t.getStart(l),text:e})}e.forEachChild(t,p)};return e.forEachChild(l,p),f}export{t as renameImportedBindingReferences};
@@ -1 +1 @@
1
- const e=[`dependencies`,`devDependencies`,`peerDependencies`];function t(t,n=`^2.0.0`){let r=JSON.parse(t),i=!1;for(let t of e){let e=r[t];if(!e)continue;if(`@solar-icons/react-perf`in e){delete e[`@solar-icons/react-perf`],e[`@solar-icons/react`]=n,i=!0;continue}let a=e[`@solar-icons/react`];(a?.startsWith(`1.`)||a?.startsWith(`^1.`)||a?.startsWith(`~1.`))&&(e[`@solar-icons/react`]=n,i=!0);let o=e[`@solar-icons/react-native`];(o?.startsWith(`1.`)||o?.startsWith(`^1.`)||o?.startsWith(`~1.`))&&(e[`@solar-icons/react-native`]=n,i=!0);for(let t of[`@solar-icons/vue`,`@solar-icons/nuxt`,`@solar-icons/svelte`,`@solar-icons/solid`,`@solar-icons/angular`]){let r=e[t];(r?.startsWith(`1.`)||r?.startsWith(`^1.`)||r?.startsWith(`~1.`))&&(e[t]=n,i=!0)}}return{code:i?`${JSON.stringify(r,null,4)}\n`:t,changed:i,diagnostics:[]}}export{t as transformPackageJson};
1
+ const e=[`dependencies`,`devDependencies`,`peerDependencies`];function t(t,n=`^2.0.0`){let r=JSON.parse(t),i=!1;for(let t of e){let e=r[t];if(!e)continue;`@solar-icons/react-perf`in e&&(delete e[`@solar-icons/react-perf`],e[`@solar-icons/react`]=n,i=!0);let a=e[`@solar-icons/react`];(a?.startsWith(`1.`)||a?.startsWith(`^1.`)||a?.startsWith(`~1.`))&&(e[`@solar-icons/react`]=n,i=!0);let o=e[`@solar-icons/react-native`];(o?.startsWith(`1.`)||o?.startsWith(`^1.`)||o?.startsWith(`~1.`))&&(e[`@solar-icons/react-native`]=n,i=!0);for(let t of[`@solar-icons/vue`,`@solar-icons/nuxt`,`@solar-icons/svelte`,`@solar-icons/solid`,`@solar-icons/angular`]){let r=e[t];(r?.startsWith(`1.`)||r?.startsWith(`^1.`)||r?.startsWith(`~1.`))&&(e[t]=n,i=!0)}}return{code:i?`${JSON.stringify(r,null,4)}\n`:t,changed:i,diagnostics:[]}}export{t as transformPackageJson};
@@ -1 +1 @@
1
- import{renameIcon as e}from"../icon-renames.mjs";import{resolve as t}from"node:path";import n from"typescript";const r=[`BoldDuotone`,`LineDuotone`,`Outline`,`Broken`,`Linear`,`Bold`];function i(e,t){return t.sort((e,t)=>t.start-e.start).reduce((e,t)=>e.slice(0,t.start)+t.text+e.slice(t.end),e)}function a(e,t){let n=e.getLineAndCharacterOfPosition(t.getStart(e));return{column:n.character+1,line:n.line+1}}function o(t){if(t===`SolarDynamicIcon`)return`SolarIcon`;let n=r.find(e=>t.endsWith(e));if(!(!n||t.startsWith(`Solar`)))return`Solar${e(t.slice(0,-n.length))}${n}`}function s(e){return`solar${e.slice(5)}`}function c(e,t=`source.ts`){let r=n.createSourceFile(t,e,n.ScriptTarget.Latest,!0),i=new Map;for(let e of r.statements){if(!n.isImportDeclaration(e)||!n.isStringLiteral(e.moduleSpecifier)||e.moduleSpecifier.text!==`@solar-icons/angular`)continue;let t=e.importClause?.namedBindings;if(!(!t||!n.isNamedImports(t)))for(let e of t.elements){let t=(e.propertyName??e.name).text,n=o(t);n&&i.set(s(`Solar${t}`),s(n))}}return i}function l(e,t){let n=[];for(let[r,i]of t){let t=RegExp(`\\b${r}\\b`,`g`);for(let a of e.matchAll(t))n.push({start:a.index,end:a.index+r.length,text:i})}let r=i(e,n);return{code:r,changed:r!==e,diagnostics:[]}}function u(e,r=`source.ts`,c=new Set){if(!r.endsWith(`.ts`))return{changed:!1,code:e,diagnostics:[]};let l=n.createSourceFile(r,e,n.ScriptTarget.Latest,!0),u=[],f=[];for(let t of l.statements){if(!n.isImportDeclaration(t)||!n.isStringLiteral(t.moduleSpecifier)||t.moduleSpecifier.text!==`@solar-icons/angular`)continue;let r=t.importClause?.namedBindings;if(!(!r||!n.isNamedImports(r)))for(let t of r.elements){let r=(t.propertyName??t.name).text,i=o(r);if(!i)continue;let a=t.name.text,c=t.propertyName?a:i;if(u.push({start:t.getStart(l),end:t.getEnd(),text:c===i?i:`${i} as ${c}`}),!t.propertyName&&a!==i){let e=r=>{n.isIdentifier(r)&&r.text===a&&r.getStart(l)!==t.name.getStart(l)&&u.push({start:r.getStart(l),end:r.getEnd(),text:i}),n.forEachChild(r,e)};n.forEachChild(l,e)}u.push(...d(e,s(`Solar${r}`),s(i)))}}let p=e=>{if(n.isPropertyAssignment(e)&&n.isIdentifier(e.name)){if(e.name.text===`templateUrl`){let i=n.isStringLiteral(e.initializer)?t(r,`..`,e.initializer.text):void 0;(!i||!c.has(i))&&f.push({code:`ANGULAR_EXTERNAL_TEMPLATE_REQUIRES_MANUAL_MIGRATION`,file:r,...a(l,e.name),message:`Skipped an external Angular template that could not be found. Review its icon selector renames manually.`})}e.name.text===`template`&&(n.isNoSubstitutionTemplateLiteral(e.initializer)||n.isStringLiteral(e.initializer))&&/\bmirrored\b/.test(e.initializer.text)&&f.push({code:`ANGULAR_MIRRORED_REQUIRES_MANUAL_MIGRATION`,file:r,...a(l,e.initializer),message:`An inline Angular template uses the removed mirrored input. Replace it with CSS transform: scaleX(-1).`,severity:`warning`})}n.forEachChild(e,p)};n.forEachChild(l,p);let m=i(e,u);return{code:m,changed:m!==e,diagnostics:f}}function d(e,t,n){let r=RegExp(`\\b${t}\\b`,`g`);return[...e.matchAll(r)].map(e=>({start:e.index,end:e.index+t.length,text:n}))}export{c as collectAngularSelectorRenames,u as transformAngular,l as transformAngularTemplate};
1
+ import{renameIcon as e}from"../icon-renames.mjs";import{resolve as t}from"node:path";import n from"typescript";const r=[`BoldDuotone`,`LineDuotone`,`Outline`,`Broken`,`Linear`,`Bold`];function i(e,t){return t.sort((e,t)=>t.start-e.start).reduce((e,t)=>e.slice(0,t.start)+t.text+e.slice(t.end),e)}function a(e,t){let n=e.getLineAndCharacterOfPosition(t.getStart(e));return{column:n.character+1,line:n.line+1}}function o(t){if(t===`SolarDynamicIcon`)return`SolarIcon`;let n=r.find(e=>t.endsWith(e));if(n&&!t.startsWith(`Solar`))return`Solar${e(t.slice(0,-n.length))}${n}`}function s(e){return`solar${e.slice(5)}`}function c(e,t=`source.ts`){let r=n.createSourceFile(t,e,n.ScriptTarget.Latest,!0),i=new Map;for(let e of r.statements){if(!n.isImportDeclaration(e)||!n.isStringLiteral(e.moduleSpecifier)||e.moduleSpecifier.text!==`@solar-icons/angular`)continue;let t=e.importClause?.namedBindings;if(t&&n.isNamedImports(t))for(let e of t.elements){let t=(e.propertyName??e.name).text,n=o(t);n&&i.set(s(`Solar${t}`),s(n))}}return i}function l(e,t){let n=[];for(let[r,i]of t){let t=RegExp(`\\b${r}\\b`,`g`);for(let a of e.matchAll(t))n.push({start:a.index,end:a.index+r.length,text:i})}let r=i(e,n);return{code:r,changed:r!==e,diagnostics:[]}}function u(e,r=`source.ts`,c=new Set){if(!r.endsWith(`.ts`))return{changed:!1,code:e,diagnostics:[]};let l=n.createSourceFile(r,e,n.ScriptTarget.Latest,!0),u=[],f=[];for(let t of l.statements){if(!n.isImportDeclaration(t)||!n.isStringLiteral(t.moduleSpecifier)||t.moduleSpecifier.text!==`@solar-icons/angular`)continue;let r=t.importClause?.namedBindings;if(r&&n.isNamedImports(r))for(let t of r.elements){let r=(t.propertyName??t.name).text,i=o(r);if(!i)continue;let a=t.name.text,c=t.propertyName?a:i;if(u.push({start:t.getStart(l),end:t.getEnd(),text:c===i?i:`${i} as ${c}`}),!t.propertyName&&a!==i){let e=r=>{n.isIdentifier(r)&&r.text===a&&r.getStart(l)!==t.name.getStart(l)&&u.push({start:r.getStart(l),end:r.getEnd(),text:i}),n.forEachChild(r,e)};n.forEachChild(l,e)}u.push(...d(e,s(`Solar${r}`),s(i)))}}let p=e=>{if(n.isPropertyAssignment(e)&&n.isIdentifier(e.name)){if(e.name.text===`templateUrl`){let i=n.isStringLiteral(e.initializer)?t(r,`..`,e.initializer.text):void 0;(!i||!c.has(i))&&f.push({code:`ANGULAR_EXTERNAL_TEMPLATE_REQUIRES_MANUAL_MIGRATION`,file:r,...a(l,e.name),message:`Skipped an external Angular template that could not be found. Review its icon selector renames manually.`})}e.name.text===`template`&&(n.isNoSubstitutionTemplateLiteral(e.initializer)||n.isStringLiteral(e.initializer))&&/\bmirrored\b/.test(e.initializer.text)&&f.push({code:`ANGULAR_MIRRORED_REQUIRES_MANUAL_MIGRATION`,file:r,...a(l,e.initializer),message:`An inline Angular template uses the removed mirrored input. Replace it with CSS transform: scaleX(-1).`,severity:`warning`})}n.forEachChild(e,p)};n.forEachChild(l,p);let m=i(e,u);return{code:m,changed:m!==e,diagnostics:f}}function d(e,t,n){let r=RegExp(`\\b${t}\\b`,`g`);return[...e.matchAll(r)].map(e=>({start:e.index,end:e.index+t.length,text:n}))}export{c as collectAngularSelectorRenames,u as transformAngular,l as transformAngularTemplate};
@@ -1 +1 @@
1
- import e from"typescript";function t(e,t){return t.sort((e,t)=>t.start-e.start).reduce((e,t)=>e.slice(0,t.start)+t.text+e.slice(t.end),e)}function n(e,t){let n=e.getLineAndCharacterOfPosition(t.getStart(e));return{column:n.character+1,line:n.line+1}}function r(t){if(e.isPropertyAssignment(t))return e.isIdentifier(t.name)||e.isStringLiteral(t.name)?t.name.text:void 0}function i(i,a=`nuxt.config.ts`){let o=e.createSourceFile(a,i,e.ScriptTarget.Latest,!0),s=[],c=[],l=t=>{if(e.isImportDeclaration(t)&&e.isStringLiteral(t.moduleSpecifier)&&t.moduleSpecifier.text===`#solar-icons/category`&&c.push({code:`NUXT_CATEGORY_IMPORT_REQUIRES_MANUAL_MIGRATION`,file:a,...n(o,t.moduleSpecifier),message:`Skipped the removed #solar-icons/category alias. Import each required v2 icon individually.`}),e.isCallExpression(t)&&e.isIdentifier(t.expression)&&t.expression.text===`defineNuxtConfig`){let n=t.arguments.find(e.isObjectLiteralExpression)?.properties.find(e=>r(e)===`solarIcons`);if(n&&e.isPropertyAssignment(n)&&e.isObjectLiteralExpression(n.initializer))for(let t of n.initializer.properties)r(t)!==`prefix`||!e.isPropertyAssignment(t)||s.push({start:t.name.getStart(o),end:t.name.getEnd(),text:`namePrefix`})}e.forEachChild(t,l)};e.forEachChild(o,l);let u=t(i,s);return{code:u,changed:u!==i,diagnostics:c}}export{i as transformNuxt};
1
+ import e from"typescript";function t(e,t){return t.sort((e,t)=>t.start-e.start).reduce((e,t)=>e.slice(0,t.start)+t.text+e.slice(t.end),e)}function n(e,t){let n=e.getLineAndCharacterOfPosition(t.getStart(e));return{column:n.character+1,line:n.line+1}}function r(t){if(e.isPropertyAssignment(t))return e.isIdentifier(t.name)||e.isStringLiteral(t.name)?t.name.text:void 0}function i(i,a=`nuxt.config.ts`){let o=e.createSourceFile(a,i,e.ScriptTarget.Latest,!0),s=[],c=[],l=t=>{if(e.isImportDeclaration(t)&&e.isStringLiteral(t.moduleSpecifier)&&t.moduleSpecifier.text===`#solar-icons/category`&&c.push({code:`NUXT_CATEGORY_IMPORT_REQUIRES_MANUAL_MIGRATION`,file:a,...n(o,t.moduleSpecifier),message:`Skipped the removed #solar-icons/category alias. Import each required v2 icon individually.`}),e.isCallExpression(t)&&e.isIdentifier(t.expression)&&t.expression.text===`defineNuxtConfig`){let n=t.arguments.find(e.isObjectLiteralExpression)?.properties.find(e=>r(e)===`solarIcons`);if(n&&e.isPropertyAssignment(n)&&e.isObjectLiteralExpression(n.initializer))for(let t of n.initializer.properties)r(t)===`prefix`&&e.isPropertyAssignment(t)&&s.push({start:t.name.getStart(o),end:t.name.getEnd(),text:`namePrefix`})}e.forEachChild(t,l)};e.forEachChild(o,l);let u=t(i,s);return{code:u,changed:u!==i,diagnostics:c}}export{i as transformNuxt};
@@ -1,2 +1,2 @@
1
- import{renameIcon as e}from"../icon-renames.mjs";import t from"typescript";const n={bold:`bold`,boldduotone:`bold-duotone`,broken:`broken`,linear:`linear`,lineduotone:`line-duotone`,outline:`outline`},r=[`BoldDuotone`,`LineDuotone`,`Outline`,`Broken`,`Linear`,`Bold`];function i(e){return e.endsWith(`Icon`)?e:`${e}Icon`}function a(e){let t=e.split(`/`).at(-1)?.replace(/[-_]/g,``).toLowerCase();return t?n[t]:void 0}function o(e){return e.replace(/([a-z\d])([A-Z])/g,`$1-$2`).replace(/([A-Z])([A-Z][a-z])/g,`$1-$2`).replace(/(\D)(\d+)/g,`$1-$2`).toLowerCase()}function s(t){let n=r.find(e=>t.endsWith(e));return i(n?`${e(t.slice(0,-n.length))}${n}`:e(t))}function c(e,t){return e.name.text===t?t:`${t} as ${e.name.text}`}function l(e,t){return t.sort((e,t)=>t.start-e.start).reduce((e,t)=>e.slice(0,t.start)+t.text+e.slice(t.end),e)}function u(e,t){let n=e.getLineAndCharacterOfPosition(t.getStart(e));return{column:n.character+1,line:n.line+1}}function d(n,r=`source.tsx`){let d=t.createSourceFile(r,n,t.ScriptTarget.Latest,!0),f=[],p=[];for(let n of d.statements){if(!t.isImportDeclaration(n)||!t.isStringLiteral(n.moduleSpecifier))continue;let l=n.moduleSpecifier.text;if(!l.startsWith(`@solar-icons/react-native`))continue;let m=n.importClause?.namedBindings;if(!m||!t.isNamedImports(m)){p.push({code:`UNSUPPORTED_REACT_NATIVE_IMPORT`,file:r,...u(d,n.moduleSpecifier),message:`Skipped non-named import from ${l}. Convert it to individual icon imports manually.`});continue}let h=l.slice(25);if(!h){for(let e of m.elements)f.push({start:e.getStart(d),end:e.getEnd(),text:c(e,s((e.propertyName??e.name).text))});continue}let g=h.match(/^\/category\/[^/]+\/([^/]+)$/),_=g?.[1]?a(g[1]):a(l);if(!_){p.push({code:`UNSUPPORTED_REACT_NATIVE_SUBPATH`,file:r,...u(d,n.moduleSpecifier),message:`Skipped unsupported React Native subpath: ${l}.`});continue}if(g){let t=m.elements.map(t=>{let n=e((t.propertyName??t.name).text);return`import { ${c(t,i(n))} } from '@solar-icons/react-native/${_}/${o(n)}'`});f.push({start:n.getStart(d),end:n.getEnd(),text:t.join(`
2
- `)});continue}f.push({start:n.moduleSpecifier.getStart(d)+1,end:n.moduleSpecifier.getEnd()-1,text:`@solar-icons/react-native/${_}`});for(let t of m.elements)f.push({start:t.getStart(d),end:t.getEnd(),text:c(t,i(e((t.propertyName??t.name).text)))});let v=new Set(m.elements.map(e=>e.name.text)),y=e=>{if(t.isJsxOpeningLikeElement(e)&&t.isIdentifier(e.tagName)&&v.has(e.tagName.text))for(let n of e.attributes.properties){if(!t.isJsxAttribute(n))continue;n.name.getText()===`mirrored`&&p.push({code:`REACT_NATIVE_MIRRORED_REQUIRES_MANUAL_MIGRATION`,file:r,...u(d,n),message:`${e.tagName.text} uses the removed mirrored prop. Replace it with style={{ transform: [{ scaleX: -1 }] }}.`,severity:`warning`});let i=n.initializer;if(n.name.getText()===`size`&&i&&t.isStringLiteral(i)){let t=Number(i.text);Number.isFinite(t)?f.push({start:i.getStart(d),end:i.getEnd(),text:`{${t}}`}):p.push({code:`REACT_NATIVE_SIZE_REQUIRES_NUMBER`,file:r,...u(d,n),message:`${e.tagName.text} has a string size. React Native v2 requires a number.`,severity:`warning`})}}t.forEachChild(e,y)};t.forEachChild(d,y)}let m=l(n,f);return{code:m,changed:m!==n,diagnostics:p}}export{d as transformReactNative};
1
+ import{renameIcon as e}from"../icon-renames.mjs";import{renameImportedBindingReferences as t}from"../import-bindings.mjs";import n from"typescript";const r={bold:`bold`,boldduotone:`bold-duotone`,broken:`broken`,linear:`linear`,lineduotone:`line-duotone`,outline:`outline`},i=[`BoldDuotone`,`LineDuotone`,`Outline`,`Broken`,`Linear`,`Bold`];function a(e){return e.endsWith(`Icon`)?e:`${e}Icon`}function o(e){let t=e.split(`/`).at(-1)?.replace(/[-_]/g,``).toLowerCase();return t?r[t]:void 0}function s(e){return e.replace(/([a-z\d])([A-Z])/g,`$1-$2`).replace(/([A-Z])([A-Z][a-z])/g,`$1-$2`).replace(/(\D)(\d+)/g,`$1-$2`).toLowerCase()}function c(t){let n=i.find(e=>t.endsWith(e));return a(n?`${e(t.slice(0,-n.length))}${n}`:e(t))}function l(e,t){return e.propertyName&&e.name.text!==t?`${t} as ${e.name.text}`:t}function u(e,t){return t.sort((e,t)=>t.start-e.start).reduce((e,t)=>e.slice(0,t.start)+t.text+e.slice(t.end),e)}function d(e,t){let n=e.getLineAndCharacterOfPosition(t.getStart(e));return{column:n.character+1,line:n.line+1}}function f(r,i=`source.tsx`){let f=n.createSourceFile(i,r,n.ScriptTarget.Latest,!0),p=[],m=[],h=new Map;for(let t of f.statements){if(!n.isImportDeclaration(t)||!n.isStringLiteral(t.moduleSpecifier))continue;let r=t.moduleSpecifier.text;if(!r.startsWith(`@solar-icons/react-native`))continue;let u=t.importClause?.namedBindings;if(!u||!n.isNamedImports(u)){m.push({code:`UNSUPPORTED_REACT_NATIVE_IMPORT`,file:i,...d(f,t.moduleSpecifier),message:`Skipped non-named import from ${r}. Convert it to individual icon imports manually.`});continue}let g=r.slice(25);if(!g){for(let e of u.elements){let t=(e.propertyName??e.name).text,n=c(t);!e.propertyName&&e.name.text!==n&&h.set(e.name.text,n),p.push({start:e.getStart(f),end:e.getEnd(),text:l(e,n)})}continue}let _=g.match(/^\/category\/[^/]+\/([^/]+)$/),v=_?.[1]?o(_[1]):o(r);if(!v){m.push({code:`UNSUPPORTED_REACT_NATIVE_SUBPATH`,file:i,...d(f,t.moduleSpecifier),message:`Skipped unsupported React Native subpath: ${r}.`});continue}if(_){let n=u.elements.map(t=>{let n=e((t.propertyName??t.name).text),r=a(n);return!t.propertyName&&t.name.text!==r&&h.set(t.name.text,r),`import { ${l(t,r)} } from '@solar-icons/react-native/${v}/${s(n)}'`});p.push({start:t.getStart(f),end:t.getEnd(),text:n.join(`
2
+ `)});continue}p.push({start:t.moduleSpecifier.getStart(f)+1,end:t.moduleSpecifier.getEnd()-1,text:`@solar-icons/react-native/${v}`});for(let t of u.elements){let n=(t.propertyName??t.name).text,r=a(e(n));!t.propertyName&&t.name.text!==r&&h.set(t.name.text,r),p.push({start:t.getStart(f),end:t.getEnd(),text:l(t,r)})}let y=new Set(u.elements.map(e=>e.name.text)),b=e=>{if(n.isJsxOpeningLikeElement(e)&&n.isIdentifier(e.tagName)&&y.has(e.tagName.text))for(let t of e.attributes.properties){if(!n.isJsxAttribute(t))continue;t.name.getText()===`mirrored`&&m.push({code:`REACT_NATIVE_MIRRORED_REQUIRES_MANUAL_MIGRATION`,file:i,...d(f,t),message:`${e.tagName.text} uses the removed mirrored prop. Replace it with style={{ transform: [{ scaleX: -1 }] }}.`,severity:`warning`});let r=t.initializer;if(t.name.getText()===`size`&&r&&n.isStringLiteral(r)){let n=Number(r.text);Number.isFinite(n)?p.push({start:r.getStart(f),end:r.getEnd(),text:`{${n}}`}):m.push({code:`REACT_NATIVE_SIZE_REQUIRES_NUMBER`,file:i,...d(f,t),message:`${e.tagName.text} has a string size. React Native v2 requires a number.`,severity:`warning`})}}n.forEachChild(e,b)};n.forEachChild(f,b)}p.push(...t(r,i,h));let g=u(r,p);return{code:g,changed:g!==r,diagnostics:m}}export{f as transformReactNative};
@@ -1 +1 @@
1
- import{renameIcon as e}from"../icon-renames.mjs";import{renameImportedBindingReferences as t}from"../import-bindings.mjs";import n from"typescript";const r={bold:`bold`,boldduotone:`bold-duotone`,broken:`broken`,linear:`linear`,lineduotone:`line-duotone`,outline:`outline`},i=new Set([`Icon`,`IconProps`]);function a(e){return e.endsWith(`Icon`)?e:`${e}Icon`}function o(e){let t=e.split(`/`).at(-1)?.replace(/[-_]/g,``).toLowerCase();return t?r[t]:void 0}function s(t,n){let i=Object.entries(r).find(([,e])=>e===n)?.[0];return a(e(i&&t.toLowerCase().endsWith(i)?t.slice(0,-i.length):t))}function c(t){let n=[`BoldDuotone`,`LineDuotone`,`Outline`,`Broken`,`Linear`,`Bold`].find(e=>t.endsWith(e));return a(n?`${e(t.slice(0,-n.length))}${n}`:e(t))}function l(e){return(e.propertyName??e.name).text}function u(e,t){return t.sort((e,t)=>t.start-e.start).reduce((e,t)=>e.slice(0,t.start)+t.text+e.slice(t.end),e)}function d(e,t){let n=e.getLineAndCharacterOfPosition(t.getStart(e));return{column:n.character+1,line:n.line+1}}function f(e,r=`source.tsx`){let a=n.createSourceFile(r,e,n.ScriptTarget.Latest,!0),f=[],p=[],m=new Map;for(let e of a.statements){if(!n.isImportDeclaration(e)||!n.isStringLiteral(e.moduleSpecifier))continue;let t=e.moduleSpecifier.text;if(!t.startsWith(`@solar-icons/react-perf`))continue;let u=t.slice(23),h=u?o(t):void 0;if(u===`/lib/types`){let o=e.importClause?.namedBindings;if(!o||!n.isNamedImports(o)){p.push({code:`UNSUPPORTED_REACT_PERF_IMPORT`,...d(a,e.moduleSpecifier),message:`Skipped non-named import from ${t}.`,file:r});continue}let s=o.elements.find(e=>!i.has(l(e)));if(s){p.push({code:`UNSUPPORTED_REACT_PERF_TYPE_EXPORT`,...d(a,s),message:`Skipped unsupported react-perf type export: ${l(s)}.`,file:r});continue}f.push({start:e.moduleSpecifier.getStart(a)+1,end:e.moduleSpecifier.getEnd()-1,text:`@solar-icons/react/lib/index`});continue}if(u&&!h){p.push({code:`UNSUPPORTED_REACT_PERF_SUBPATH`,...d(a,e.moduleSpecifier),message:`Skipped unsupported react-perf subpath: ${t}.`,file:r});continue}let g=e.importClause?.namedBindings;if(!g||!n.isNamedImports(g)){p.push({code:`UNSUPPORTED_REACT_PERF_IMPORT`,...d(a,e.moduleSpecifier),message:`Skipped non-named import from ${t}.`,file:r});continue}f.push({start:e.moduleSpecifier.getStart(a)+1,end:e.moduleSpecifier.getEnd()-1,text:h?`@solar-icons/react/${h}`:`@solar-icons/react`});for(let e of g.elements){let t=l(e),n=h?s(t,h):c(t),r=e.name.text,i=!!e.propertyName,o=i?r:n;!i&&r!==n&&m.set(r,n),f.push({start:e.getStart(a),end:e.getEnd(),text:o===n?n:`${n} as ${o}`})}let _=new Set(g.elements.map(e=>e.name.text)),v=e=>{if(n.isJsxOpeningLikeElement(e)&&n.isIdentifier(e.tagName)&&_.has(e.tagName.text))for(let t of e.attributes.properties)!n.isJsxAttribute(t)||t.name.getText()!==`mirrored`||p.push({code:`REACT_MIRRORED_REQUIRES_MANUAL_MIGRATION`,file:r,...d(a,t),message:`${e.tagName.text} uses the removed mirrored prop. Replace it with style={{ transform: 'scaleX(-1)' }}.`,severity:`warning`});n.forEachChild(e,v)};n.forEachChild(a,v)}let h=e=>{n.isStringLiteral(e)&&e.text===`@solar-icons/react-perf`&&!n.isImportDeclaration(e.parent)&&f.push({start:e.getStart(a)+1,end:e.getEnd()-1,text:`@solar-icons/react`}),n.forEachChild(e,h)};n.forEachChild(a,h),f.push(...t(e,r,m));let g=u(e,f);return{code:g,changed:g!==e,diagnostics:p}}export{f as transformReactPerf};
1
+ import{renameIcon as e}from"../icon-renames.mjs";import{renameImportedBindingReferences as t}from"../import-bindings.mjs";import n from"typescript";const r={bold:`bold`,boldduotone:`bold-duotone`,broken:`broken`,linear:`linear`,lineduotone:`line-duotone`,outline:`outline`},i=new Set([`Icon`,`IconProps`]);function a(e){return e.endsWith(`Icon`)?e:`${e}Icon`}function o(e){let t=e.split(`/`).at(-1)?.replace(/[-_]/g,``).toLowerCase();return t?r[t]:void 0}function s(t,n){let i=Object.entries(r).find(([,e])=>e===n)?.[0],o=i&&t.toLowerCase().endsWith(i)?t.slice(0,-i.length):t;return a(e(o))}function c(t){let n=[`BoldDuotone`,`LineDuotone`,`Outline`,`Broken`,`Linear`,`Bold`].find(e=>t.endsWith(e));return a(n?`${e(t.slice(0,-n.length))}${n}`:e(t))}function l(e){return(e.propertyName??e.name).text}function u(e,t){return t.sort((e,t)=>t.start-e.start).reduce((e,t)=>e.slice(0,t.start)+t.text+e.slice(t.end),e)}function d(e,t){let n=e.getLineAndCharacterOfPosition(t.getStart(e));return{column:n.character+1,line:n.line+1}}function f(e,r=`source.tsx`){let a=n.createSourceFile(r,e,n.ScriptTarget.Latest,!0),f=[],p=[],m=new Map;for(let e of a.statements){if(!n.isImportDeclaration(e)||!n.isStringLiteral(e.moduleSpecifier))continue;let t=e.moduleSpecifier.text;if(!t.startsWith(`@solar-icons/react-perf`))continue;let u=t.slice(23),h=u?o(t):void 0;if(u===`/lib/types`){let o=e.importClause?.namedBindings;if(!o||!n.isNamedImports(o)){p.push({code:`UNSUPPORTED_REACT_PERF_IMPORT`,...d(a,e.moduleSpecifier),message:`Skipped non-named import from ${t}.`,file:r});continue}let s=o.elements.find(e=>!i.has(l(e)));if(s){p.push({code:`UNSUPPORTED_REACT_PERF_TYPE_EXPORT`,...d(a,s),message:`Skipped unsupported react-perf type export: ${l(s)}.`,file:r});continue}f.push({start:e.moduleSpecifier.getStart(a)+1,end:e.moduleSpecifier.getEnd()-1,text:`@solar-icons/react/lib/index`});continue}if(u&&!h){p.push({code:`UNSUPPORTED_REACT_PERF_SUBPATH`,...d(a,e.moduleSpecifier),message:`Skipped unsupported react-perf subpath: ${t}.`,file:r});continue}let g=e.importClause?.namedBindings;if(!g||!n.isNamedImports(g)){p.push({code:`UNSUPPORTED_REACT_PERF_IMPORT`,...d(a,e.moduleSpecifier),message:`Skipped non-named import from ${t}.`,file:r});continue}f.push({start:e.moduleSpecifier.getStart(a)+1,end:e.moduleSpecifier.getEnd()-1,text:h?`@solar-icons/react/${h}`:`@solar-icons/react`});for(let e of g.elements){let t=l(e),n=h?s(t,h):c(t),r=e.name.text,i=!!e.propertyName,o=i?r:n;!i&&r!==n&&m.set(r,n),f.push({start:e.getStart(a),end:e.getEnd(),text:o===n?n:`${n} as ${o}`})}let _=new Set(g.elements.map(e=>e.name.text)),v=e=>{if(n.isJsxOpeningLikeElement(e)&&n.isIdentifier(e.tagName)&&_.has(e.tagName.text))for(let t of e.attributes.properties)n.isJsxAttribute(t)&&t.name.getText()===`mirrored`&&p.push({code:`REACT_MIRRORED_REQUIRES_MANUAL_MIGRATION`,file:r,...d(a,t),message:`${e.tagName.text} uses the removed mirrored prop. Replace it with style={{ transform: 'scaleX(-1)' }}.`,severity:`warning`});n.forEachChild(e,v)};n.forEachChild(a,v)}let h=e=>{n.isStringLiteral(e)&&e.text===`@solar-icons/react-perf`&&!n.isImportDeclaration(e.parent)&&f.push({start:e.getStart(a)+1,end:e.getEnd()-1,text:`@solar-icons/react`}),n.forEachChild(e,h)};n.forEachChild(a,h),f.push(...t(e,r,m));let g=u(e,f);return{code:g,changed:g!==e,diagnostics:p}}export{f as transformReactPerf};
@@ -1,2 +1,2 @@
1
- import{renameIcon as e}from"../icon-renames.mjs";import{renameImportedBindingReferences as t}from"../import-bindings.mjs";import n from"typescript";const r={Bold:`bold`,BoldDuotone:`bold-duotone`,Broken:`broken`,Linear:`linear`,LineDuotone:`line-duotone`,Outline:`outline`};function i(e){return e.endsWith(`Icon`)?e:`${e}Icon`}function a(e){return e.attributes.properties.find(e=>n.isJsxAttribute(e)&&e.name.getText()===`weight`)}function o(e){if(!e)return`Linear`;let t=e.initializer;if(t&&n.isStringLiteral(t))return t.text;if(t&&n.isJsxExpression(t)){let e=t.expression;if(e&&n.isStringLiteral(e))return e.text}}function s(e,t){return t.sort((e,t)=>t.start-e.start).reduce((e,t)=>e.slice(0,t.start)+t.text+e.slice(t.end),e)}function c(e,t){let n=e.getLineAndCharacterOfPosition(t.getStart(e));return{column:n.character+1,line:n.line+1}}function l(r,i){let a=[],o=new Map;for(let t of i.statements){if(!n.isImportDeclaration(t)||!n.isStringLiteral(t.moduleSpecifier)||!t.moduleSpecifier.text.startsWith(`@solar-icons/react`))continue;let r=t.importClause?.namedBindings;if(!(!r||!n.isNamedImports(r)))for(let t of r.elements){if(!t.propertyName)continue;let n=t.propertyName.text,r=t.name.text,s=n.slice(0,-4);!n.endsWith(`Icon`)||r!==s&&e(r)!==s||(a.push({end:t.getEnd(),start:t.getStart(i),text:n}),o.set(r,n))}}return[...a,...t(r,i.fileName,o)]}function u(u,d=`source.tsx`,f=`static`){let p=n.createSourceFile(d,u,n.ScriptTarget.Latest,!0),m=[],h=[],g=new Map;for(let t of p.statements){if(!n.isImportDeclaration(t)||!n.isStringLiteral(t.moduleSpecifier))continue;let s=t.moduleSpecifier.text;if(s===`@solar-icons/react/category`){m.push({code:`REACT_CATEGORY_IMPORT_REQUIRES_MANUAL_MIGRATION`,...c(p,t.moduleSpecifier),message:`Skipped a React category import. Replace each category member with an individual v2 icon import.`,file:d});continue}if(s!==`@solar-icons/react`&&s!==`@solar-icons/react/ssr`)continue;let l=t.importClause?.namedBindings,_=!!t.importClause?.name;if(_&&m.push({code:`UNSUPPORTED_REACT_IMPORT`,...c(p,t.moduleSpecifier),message:`Skipped a default React namespace import. Convert it to individual icon imports manually.`,file:d}),!l||!n.isNamedImports(l)){_||m.push({code:`UNSUPPORTED_REACT_IMPORT`,...c(p,t.moduleSpecifier),message:`Skipped a default or namespace React import. Convert it to individual icon imports manually.`,file:d});continue}if(l.elements.filter(e=>{let t=(e.propertyName??e.name).text;return t===`SolarProvider`||t===`useSolar`}).length>0){m.push({code:`REACT_PROVIDER_REQUIRES_MANUAL_MIGRATION`,...c(p,t.moduleSpecifier),message:`Skipped a legacy SolarProvider or useSolar import. Its v1 context API and weight inheritance require manual migration.`,file:d});continue}if(l.elements.every(e=>(e.propertyName??e.name).text.endsWith(`Icon`)))continue;let v=new Map;for(let e of l.elements)v.set(e.name.text,{dynamic:!1,dynamicWeightAttributes:[],mirroredAttributes:[],styles:new Set,tagNames:[],weightAttributes:[]});let y=e=>{if(n.isJsxOpeningLikeElement(e)&&n.isIdentifier(e.tagName)){let t=v.get(e.tagName.text);if(t){t.tagNames.push(e.tagName);let i=a(e),s=e.attributes.properties.find(e=>n.isJsxAttribute(e)&&e.name.getText()===`mirrored`);s&&t.mirroredAttributes.push(s);let c=o(i),l=c&&r[c];l?(t.styles.add(l),i&&t.weightAttributes.push(i)):(t.dynamic=!0,i&&t.dynamicWeightAttributes.push(i))}}n.isJsxClosingElement(e)&&n.isIdentifier(e.tagName)&&v.get(e.tagName.text)?.tagNames.push(e.tagName),n.forEachChild(e,y)};n.forEachChild(p,y);let b=[...v.entries()].filter(([,e])=>e.styles.size===0&&!e.dynamic);if(b.length>0){m.push({code:`REACT_IMPORT_REQUIRES_REVIEW`,...c(p,t.moduleSpecifier),message:`Skipped React import because ${b.map(([e])=>e).join(`, `)} is not used as JSX in this file.`,file:d});continue}let x=[];for(let t of l.elements){let n=t.name.text,r=(t.propertyName??t.name).text,a=v.get(n),o=f===`dynamic`||a.dynamic||a.styles.size!==1?`dynamic`:[...a.styles][0],s=i(e(r)),l=!!t.propertyName,_=l?n:s,y=_===s?s:`${s} as ${_}`;if(x.push(`import { ${y} } from '@solar-icons/react/${o}'`),!l&&n!==s&&g.set(n,s),f===`static`&&a.dynamicWeightAttributes.length>0){let e=a.dynamicWeightAttributes[0];if(!e)continue;m.push({code:`REACT_DYNAMIC_WEIGHT_FALLBACK`,file:d,...c(p,e),message:`${n} has a dynamic weight, so it was migrated to @solar-icons/react/dynamic instead of a static style path.`,severity:`warning`})}for(let e of a.mirroredAttributes)m.push({code:`REACT_MIRRORED_REQUIRES_MANUAL_MIGRATION`,file:d,...c(p,e),message:`${n} uses the removed mirrored prop. Replace it with style={{ transform: 'scaleX(-1)' }}.`,severity:`warning`});if(o!==`dynamic`)for(let e of a.weightAttributes){let t=e.getStart(p);h.push({start:/\s/.test(u[t-1]??``)?t-1:t,end:e.getEnd(),text:``})}}h.push({start:t.getStart(p),end:t.getEnd(),text:x.join(`
1
+ import{renameIcon as e}from"../icon-renames.mjs";import{renameImportedBindingReferences as t}from"../import-bindings.mjs";import n from"typescript";const r={Bold:`bold`,BoldDuotone:`bold-duotone`,Broken:`broken`,Linear:`linear`,LineDuotone:`line-duotone`,Outline:`outline`};function i(e){return e.endsWith(`Icon`)?e:`${e}Icon`}function a(e){return e.attributes.properties.find(e=>n.isJsxAttribute(e)&&e.name.getText()===`weight`)}function o(e){if(!e)return`Linear`;let t=e.initializer;if(t&&n.isStringLiteral(t))return t.text;if(t&&n.isJsxExpression(t)){let e=t.expression;if(e&&n.isStringLiteral(e))return e.text}}function s(e,t){return t.sort((e,t)=>t.start-e.start).reduce((e,t)=>e.slice(0,t.start)+t.text+e.slice(t.end),e)}function c(e,t){let n=e.getLineAndCharacterOfPosition(t.getStart(e));return{column:n.character+1,line:n.line+1}}function l(r,i){let a=[],o=new Map;for(let t of i.statements){if(!n.isImportDeclaration(t)||!n.isStringLiteral(t.moduleSpecifier)||!t.moduleSpecifier.text.startsWith(`@solar-icons/react`))continue;let r=t.importClause?.namedBindings;if(r&&n.isNamedImports(r))for(let t of r.elements){if(!t.propertyName)continue;let n=t.propertyName.text,r=t.name.text,s=n.slice(0,-4);!n.endsWith(`Icon`)||r!==s&&e(r)!==s||(a.push({end:t.getEnd(),start:t.getStart(i),text:n}),o.set(r,n))}}return[...a,...t(r,i.fileName,o)]}function u(u,d=`source.tsx`,f=`static`){let p=n.createSourceFile(d,u,n.ScriptTarget.Latest,!0),m=[],h=[],g=new Map;for(let t of p.statements){if(!n.isImportDeclaration(t)||!n.isStringLiteral(t.moduleSpecifier))continue;let s=t.moduleSpecifier.text;if(s===`@solar-icons/react/category`){m.push({code:`REACT_CATEGORY_IMPORT_REQUIRES_MANUAL_MIGRATION`,...c(p,t.moduleSpecifier),message:`Skipped a React category import. Replace each category member with an individual v2 icon import.`,file:d});continue}if(s!==`@solar-icons/react`&&s!==`@solar-icons/react/ssr`)continue;let l=t.importClause?.namedBindings,_=!!t.importClause?.name;if(_&&m.push({code:`UNSUPPORTED_REACT_IMPORT`,...c(p,t.moduleSpecifier),message:`Skipped a default React namespace import. Convert it to individual icon imports manually.`,file:d}),!l||!n.isNamedImports(l)){_||m.push({code:`UNSUPPORTED_REACT_IMPORT`,...c(p,t.moduleSpecifier),message:`Skipped a default or namespace React import. Convert it to individual icon imports manually.`,file:d});continue}if(l.elements.filter(e=>{let t=(e.propertyName??e.name).text;return t===`SolarProvider`||t===`useSolar`}).length>0){m.push({code:`REACT_PROVIDER_REQUIRES_MANUAL_MIGRATION`,...c(p,t.moduleSpecifier),message:`Skipped a legacy SolarProvider or useSolar import. Its v1 context API and weight inheritance require manual migration.`,file:d});continue}if(l.elements.every(e=>(e.propertyName??e.name).text.endsWith(`Icon`)))continue;let v=new Map;for(let e of l.elements)v.set(e.name.text,{dynamic:!1,dynamicWeightAttributes:[],mirroredAttributes:[],styles:new Set,tagNames:[],weightAttributes:[]});let y=e=>{if(n.isJsxOpeningLikeElement(e)&&n.isIdentifier(e.tagName)){let t=v.get(e.tagName.text);if(t){t.tagNames.push(e.tagName);let i=a(e),s=e.attributes.properties.find(e=>n.isJsxAttribute(e)&&e.name.getText()===`mirrored`);s&&t.mirroredAttributes.push(s);let c=o(i),l=c&&r[c];l?(t.styles.add(l),i&&t.weightAttributes.push(i)):(t.dynamic=!0,i&&t.dynamicWeightAttributes.push(i))}}n.isJsxClosingElement(e)&&n.isIdentifier(e.tagName)&&v.get(e.tagName.text)?.tagNames.push(e.tagName),n.forEachChild(e,y)};n.forEachChild(p,y);let b=[...v.entries()].filter(([,e])=>e.styles.size===0&&!e.dynamic);if(b.length>0){m.push({code:`REACT_IMPORT_REQUIRES_REVIEW`,...c(p,t.moduleSpecifier),message:`Skipped React import because ${b.map(([e])=>e).join(`, `)} is not used as JSX in this file.`,file:d});continue}let x=[];for(let t of l.elements){let n=t.name.text,r=(t.propertyName??t.name).text,a=v.get(n),o=f===`dynamic`||a.dynamic||a.styles.size!==1?`dynamic`:[...a.styles][0],s=i(e(r)),l=!!t.propertyName,_=l?n:s,y=_===s?s:`${s} as ${_}`;if(x.push(`import { ${y} } from '@solar-icons/react/${o}'`),!l&&n!==s&&g.set(n,s),f===`static`&&a.dynamicWeightAttributes.length>0){let e=a.dynamicWeightAttributes[0];if(!e)continue;m.push({code:`REACT_DYNAMIC_WEIGHT_FALLBACK`,file:d,...c(p,e),message:`${n} has a dynamic weight, so it was migrated to @solar-icons/react/dynamic instead of a static style path.`,severity:`warning`})}for(let e of a.mirroredAttributes)m.push({code:`REACT_MIRRORED_REQUIRES_MANUAL_MIGRATION`,file:d,...c(p,e),message:`${n} uses the removed mirrored prop. Replace it with style={{ transform: 'scaleX(-1)' }}.`,severity:`warning`});if(o!==`dynamic`)for(let e of a.weightAttributes){let t=e.getStart(p);h.push({start:/\s/.test(u[t-1]??``)?t-1:t,end:e.getEnd(),text:``})}}h.push({start:t.getStart(p),end:t.getEnd(),text:x.join(`
2
2
  `)})}h.push(...t(u,d,g)),h.push(...l(u,p));let _=s(u,h);return{code:_,changed:_!==u,diagnostics:m}}export{u as transformReact};
package/package.json CHANGED
@@ -1,17 +1,24 @@
1
1
  {
2
2
  "name": "@solar-icons/codemod",
3
- "version": "2.0.0-beta.4",
3
+ "version": "2.1.0",
4
4
  "private": false,
5
- "publishConfig": {
6
- "access": "public"
7
- },
8
5
  "description": "Conservative migration codemods for Solar Icons",
6
+ "keywords": [
7
+ "codemod",
8
+ "migration",
9
+ "solar-icons"
10
+ ],
11
+ "license": "MIT",
12
+ "author": {
13
+ "name": "Saoudi Hakim",
14
+ "email": "saoudi-hakim@outlook.com",
15
+ "url": "https://hakimsaoudi.dev"
16
+ },
9
17
  "repository": {
10
18
  "type": "git",
11
19
  "url": "git+https://github.com/saoudi-h/solar-icons.git",
12
20
  "directory": "packages/codemod"
13
21
  },
14
- "type": "module",
15
22
  "bin": {
16
23
  "codemod": "./dist/cli.mjs",
17
24
  "solar-icons-migrate": "./dist/cli.mjs"
@@ -22,6 +29,7 @@
22
29
  "LICENSE",
23
30
  "LICENSE-THIRD-PARTY"
24
31
  ],
32
+ "type": "module",
25
33
  "types": "./dist/index.d.mts",
26
34
  "exports": {
27
35
  "./package.json": "./package.json",
@@ -30,50 +38,39 @@
30
38
  "import": "./dist/index.mjs"
31
39
  }
32
40
  },
41
+ "publishConfig": {
42
+ "access": "public"
43
+ },
33
44
  "dependencies": {
34
- "@clack/prompts": "^1.7.0",
35
- "@vue/compiler-sfc": "^3.5.39",
45
+ "@clack/prompts": "^1.8.1",
46
+ "@vue/compiler-sfc": "^3.5.41",
36
47
  "commander": "^15.0.0",
37
48
  "picocolors": "^1.1.1",
38
- "svelte": "^5.56.4",
49
+ "svelte": "^5.57.0",
39
50
  "typescript": "^6.0.3"
40
51
  },
41
52
  "devDependencies": {
42
- "@tala-tools/eslint": "0.1.4",
43
- "@tala-tools/prettier": "0.0.3",
44
- "@tala-tools/tsconfig": "0.0.1",
45
- "@types/node": "^26.1.1",
46
- "prettier": "^3.9.4",
53
+ "@tala-tools/tsconfig": "0.0.2",
54
+ "@types/node": "^26.5.1",
47
55
  "rimraf": "^6.1.3",
48
- "tsdown": "^0.22.4",
49
- "tsx": "^4.23.0",
50
- "vitest": "^4.1.10"
56
+ "tsdown": "^0.22.14",
57
+ "tsx": "^4.23.13",
58
+ "vitest": "^4.1.11"
51
59
  },
52
60
  "engines": {
53
61
  "node": ">=18"
54
62
  },
55
- "keywords": [
56
- "solar-icons",
57
- "codemod",
58
- "migration"
59
- ],
60
- "author": {
61
- "name": "Saoudi Hakim",
62
- "url": "https://hakimsaoudi.dev",
63
- "email": "saoudi-hakim@outlook.com"
64
- },
65
- "license": "MIT",
66
63
  "scripts": {
67
64
  "build": "pnpm copy:licenses && tsdown -l error",
68
65
  "copy:licenses": "cp ../../LICENSE ./LICENSE && cp ../../LICENSE-THIRD-PARTY ./LICENSE-THIRD-PARTY",
69
- "lint": "eslint . --max-warnings 0",
70
- "lint:fix": "eslint . --fix",
71
- "format": "prettier \"**/*\" --ignore-unknown --list-different",
72
- "format:fix": "prettier \"**/*\" --ignore-unknown --write",
66
+ "lint": "oxlint --deny-warnings .",
67
+ "lint:fix": "oxlint --fix .",
68
+ "format": "oxfmt --check .",
69
+ "format:fix": "oxfmt --write .",
73
70
  "clean": "rimraf *.tsbuildinfo node_modules dist",
74
71
  "test": "vitest run",
75
72
  "test:fixtures": "tsx scripts/run-fixtures.ts",
76
- "typecheck": "tsgo --noEmit",
73
+ "typecheck": "tsc --noEmit",
77
74
  "pre-commit": "lint-staged"
78
75
  }
79
76
  }