1import {
2 createFileTreeIconResolver,
3 getBuiltInSpriteSheet,
4 type FileTreeIcons,
5} from "@pierre/trees";
6import { VIDEO_FILE_EXTENSIONS } from "@t3tools/shared/video";
7import { fileIconPathForMimeType } from "@t3tools/shared/filePreview";
8
9export interface PierreIconResolution {
10 name: string;
11 token?: string;
12}
13
14const PIERRE_ICON_SPRITE_ID = "t3code-pierre-file-icon-sprite";
15
16const T3_FILE_ICON_SPRITE = `
17<svg xmlns="http://www.w3.org/2000/svg" width="0" height="0" aria-hidden="true">
18 <!-- Lucide Film icon, ISC license. -->
19 <symbol id="t3-file-icon-video" viewBox="0 0 24 24">
20 <g fill="none" stroke="#a631be" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
21 <rect width="18" height="18" x="3" y="3" rx="2" />
22 <path d="M7 3v18M3 7.5h4M3 12h18M3 16.5h4M17 3v18M17 7.5h4M17 16.5h4" />
23 </g>
24 </symbol>
25 <symbol id="t3-file-icon-agents" viewBox="0 0 32 32">
26 <path fill="currentColor" d="M27.2 16c0-6.19-5.01-11.2-11.2-11.2C9.81 4.8 4.8 9.81 4.8 16S9.81 27.2 16 27.2c6.19 0 11.2-5.01 11.2-11.2Zm-5.6 2.1a1.4 1.4 0 1 1 0 2.8h-4.2a1.4 1.4 0 1 1 0-2.8Zm-11.2-6.8c.622-.373 1.42-.208 1.84.361l.079.119 2.1 3.5.088.171c.15.351.15.748 0 1.1l-.088.171-2.1 3.5a1.4 1.4 0 0 1-2.4-1.44L11.59 16l-1.67-2.78-.067-.127c-.302-.642-.075-1.42.547-1.79ZM30 16c0 7.73-6.27 14-14 14S2 23.73 2 16 8.27 2 16 2s14 6.27 14 14Z" />
27 </symbol>
28 <symbol id="t3-file-icon-pnpm" viewBox="0 0 32 32">
29 <path fill="#f9ad00" d="M30 10.75h-8.749V2H30Zm-9.626 0h-8.75V2h8.75Zm-9.625 0H2V2h8.749ZM30 20.375h-8.749v-8.75H30Z" />
30 <path fill="currentColor" d="M20.374 20.375h-8.75v-8.75h8.75Zm0 9.625h-8.75v-8.75h8.75ZM30 30h-8.749v-8.75H30Zm-19.251 0H2v-8.75h8.749Z" />
31 </symbol>
32 <!-- Lucide Loader Circle icon, ISC license. -->
33 <symbol id="t3-tree-icon-loading" viewBox="0 0 24 24">
34 <path fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" d="M21 12a9 9 0 1 1-6.219-8.56" />
35 </symbol>
36 <!-- Lucide Diff icon, ISC license. -->
37 <symbol id="t3-file-icon-diff" viewBox="0 0 24 24">
38 <path fill="none" style="stroke: light-dark(#199f43, #5ecc71)" stroke-width="2" stroke-linecap="round" d="M12 3v14M5 10h14M5 21h14" />
39 </symbol>
40 <!-- Lucide Code Xml icon, ISC license. -->
41 <symbol id="t3-file-icon-xml" viewBox="0 0 24 24">
42 <path fill="none" style="stroke: light-dark(#d47628, #ffa359)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" d="m18 16 4-4-4-4M6 8l-4 4 4 4M14.5 4l-5 16" />
43 </symbol>
44 <!-- Language logos from Simple Icons, CC0. -->
45 <symbol id="t3-file-icon-csharp" viewBox="0 0 24 24">
46 <path style="fill: light-dark(#693acf, #9d6afb)" d="M1.194 7.543v8.913c0 1.103.588 2.122 1.544 2.674l7.718 4.456a3.086 3.086 0 0 0 3.088 0l7.718-4.456a3.087 3.087 0 0 0 1.544-2.674V7.543a3.084 3.084 0 0 0-1.544-2.673L13.544.414a3.086 3.086 0 0 0-3.088 0L2.738 4.87a3.085 3.085 0 0 0-1.544 2.673Zm5.403 2.914v3.087a.77.77 0 0 0 .772.772.773.773 0 0 0 .772-.772.773.773 0 0 1 1.317-.546.775.775 0 0 1 .226.546 2.314 2.314 0 1 1-4.631 0v-3.087c0-.615.244-1.203.679-1.637a2.312 2.312 0 0 1 3.274 0c.434.434.678 1.023.678 1.637a.769.769 0 0 1-.226.545.767.767 0 0 1-1.091 0 .77.77 0 0 1-.226-.545.77.77 0 0 0-.772-.772.771.771 0 0 0-.772.772Zm12.35 3.087a.77.77 0 0 1-.772.772h-.772v.772a.773.773 0 0 1-1.544 0v-.772h-1.544v.772a.773.773 0 0 1-1.317.546.775.775 0 0 1-.226-.546v-.772H12a.771.771 0 1 1 0-1.544h.772v-1.543H12a.77.77 0 1 1 0-1.544h.772v-.772a.773.773 0 0 1 1.317-.546.775.775 0 0 1 .226.546v.772h1.544v-.772a.773.773 0 0 1 1.544 0v.772h.772a.772.772 0 0 1 0 1.544h-.772v1.543h.772a.776.776 0 0 1 .772.772Zm-3.088-2.315h-1.544v1.543h1.544v-1.543Z" />
47 </symbol>
48 <symbol id="t3-file-icon-dart" viewBox="0 0 24 24">
49 <path style="fill: light-dark(#1ca1c7, #68cdf2)" d="M4.105 4.105S9.158 1.58 11.684.316a3.079 3.079 0 0 1 1.481-.315c.766.047 1.677.788 1.677.788L24 9.948v9.789h-4.263V24H9.789l-9-9C.303 14.5 0 13.795 0 13.105c0-.319.18-.818.316-1.105l3.789-7.895zm.679.679v11.787c.002.543.021 1.024.498 1.508L10.204 23h8.533v-4.263L4.784 4.784zm12.055-.678c-.899-.896-1.809-1.78-2.74-2.643-.302-.267-.567-.468-1.07-.462-.37.014-.87.195-.87.195L6.341 4.105l10.498.001z" />
50 </symbol>
51 <symbol id="t3-file-icon-elixir" viewBox="0 0 24 24">
52 <path style="fill: light-dark(#a631be, #d568ea)" d="M19.793 16.575c0 3.752-2.927 7.426-7.743 7.426-5.249 0-7.843-3.71-7.843-8.29 0-5.21 3.892-12.952 8-15.647a.397.397 0 0 1 .61.371 9.716 9.716 0 0 0 1.694 6.518c.522.795 1.092 1.478 1.763 2.352.94 1.227 1.637 1.906 2.644 3.842l.015.028a7.107 7.107 0 0 1 .86 3.4z" />
53 </symbol>
54 <symbol id="t3-file-icon-haskell" viewBox="0 0 24 24">
55 <path style="fill: light-dark(#693acf, #9d6afb)" d="M0 3.535L5.647 12 0 20.465h4.235L9.883 12 4.235 3.535zm5.647 0L11.294 12l-5.647 8.465h4.235l3.53-5.29 3.53 5.29h4.234L9.883 3.535zm8.941 4.938l1.883 2.822H24V8.473zm2.824 4.232l1.882 2.822H24v-2.822z" />
56 </symbol>
57 <symbol id="t3-file-icon-java" viewBox="0 0 24 24">
58 <path style="fill: light-dark(#d47628, #ffa359)" d="M11.915 0 11.7.215C9.515 2.4 7.47 6.39 6.046 10.483c-1.064 1.024-3.633 2.81-3.711 3.551-.093.87 1.746 2.611 1.55 3.235-.198.625-1.304 1.408-1.014 1.939.1.188.823.011 1.277-.491a13.389 13.389 0 0 0-.017 2.14c.076.906.27 1.668.643 2.232.372.563.956.911 1.667.911.397 0 .727-.114 1.024-.264.298-.149.571-.33.91-.5.68-.34 1.634-.666 3.53-.604 1.903.062 2.872.39 3.559.704.687.314 1.15.664 1.925.664.767 0 1.395-.336 1.807-.9.412-.563.631-1.33.72-2.24.06-.623.055-1.32 0-2.066.454.45 1.117.604 1.213.424.29-.53-.816-1.314-1.013-1.937-.198-.624 1.642-2.366 1.549-3.236-.08-.748-2.707-2.568-3.748-3.586C16.428 6.374 14.308 2.394 12.13.215zm.175 6.038a2.95 2.95 0 0 1 2.943 2.942 2.95 2.95 0 0 1-2.943 2.943A2.95 2.95 0 0 1 9.148 8.98a2.95 2.95 0 0 1 2.942-2.942zM8.685 7.983a3.515 3.515 0 0 0-.145.997c0 1.951 1.6 3.55 3.55 3.55 1.95 0 3.55-1.598 3.55-3.55 0-.329-.046-.648-.132-.951.334.095.64.208.915.336a42.699 42.699 0 0 1 2.042 5.829c.678 2.545 1.01 4.92.846 6.607-.082.844-.29 1.51-.606 1.94-.315.431-.713.651-1.315.651-.593 0-.932-.27-1.673-.61-.741-.338-1.825-.694-3.792-.758-1.974-.064-3.073.293-3.821.669-.375.188-.659.373-.911.5s-.466.2-.752.2c-.53 0-.876-.209-1.16-.64-.285-.43-.474-1.101-.545-1.948-.141-1.693.176-4.069.823-6.614a43.155 43.155 0 0 1 1.934-5.783c.348-.167.749-.31 1.192-.425zm-3.382 4.362a.216.216 0 0 1 .13.031c-.166.56-.323 1.116-.463 1.665a33.849 33.849 0 0 0-.547 2.555 3.9 3.9 0 0 0-.2-.39c-.58-1.012-.914-1.642-1.16-2.08.315-.24 1.679-1.755 2.24-1.781zm13.394.01c.562.027 1.926 1.543 2.24 1.783-.246.438-.58 1.068-1.16 2.08a4.428 4.428 0 0 0-.163.309 32.354 32.354 0 0 0-.562-2.49 40.579 40.579 0 0 0-.482-1.652.216.216 0 0 1 .127-.03z" />
59 </symbol>
60 <symbol id="t3-file-icon-kotlin" viewBox="0 0 24 24">
61 <path style="fill: light-dark(#693acf, #9d6afb)" d="M24 24H0V0h24L12 12Z" />
62 </symbol>
63 <symbol id="t3-file-icon-lua" viewBox="0 0 24 24">
64 <path style="fill: light-dark(#1a85d4, #69b1ff)" d="M.38 10.377l-.272-.037c-.048.344-.082.695-.101 1.041l.275.016c.018-.34.051-.682.098-1.02zM4.136 3.289l-.184-.205c-.258.232-.509.48-.746.734l.202.188c.231-.248.476-.49.728-.717zM5.769 2.059l-.146-.235c-.296.186-.586.385-.863.594l.166.219c.27-.203.554-.399.843-.578zM1.824 18.369c.185.297.384.586.593.863l.22-.164c-.205-.271-.399-.555-.58-.844l-.233.145zM1.127 16.402l-.255.104c.129.318.274.635.431.943l.005.01.245-.125-.005-.01c-.153-.301-.295-.611-.421-.922zM.298 9.309l.269.063c.076-.332.168-.664.272-.986l-.261-.087c-.108.332-.202.672-.28 1.01zM.274 12.42l-.275.01c.012.348.04.699.083 1.043l.273-.033c-.042-.336-.069-.68-.081-1.02zM.256 14.506c.073.34.162.682.264 1.014l.263-.08c-.1-.326-.187-.658-.258-.99l-.269.056zM11.573.275L11.563 0c-.348.012-.699.039-1.044.082l.034.273c.338-.041.68-.068 1.02-.08zM23.221 8.566c.1.326.186.66.256.992l.27-.059c-.072-.34-.16-.682-.262-1.014l-.264.081zM17.621 1.389c-.309-.164-.627-.314-.947-.449l-.107.252c.314.133.625.281.926.439l.128-.242zM15.693.572c-.332-.105-.67-.199-1.01-.277l-.063.268c.332.076.664.168.988.273l.085-.264zM6.674 1.545c.298-.15.606-.291.916-.418L7.486.873c-.317.127-.632.272-.937.428l-.015.008.125.244.015-.008zM23.727 11.588l.275-.01a11.797 11.797 0 0 0-.082-1.045l-.273.033c.041.338.068.682.08 1.022zM13.654.105c-.346-.047-.696-.08-1.043-.098l-.014.273c.339.018.683.051 1.019.098l.038-.273zM9.544.527l-.058-.27c-.34.072-.681.16-1.014.264l.081.262c.325-.099.659-.185.991-.256zM1.921 5.469l.231.15c.185-.285.384-.566.592-.834l-.217-.17c-.213.276-.417.563-.606.854zM.943 7.318l.253.107c.132-.313.28-.625.439-.924l-.243-.128c-.163.307-.314.625-.449.945zM18.223 21.943l.145.234c.295-.186.586-.385.863-.594l-.164-.219c-.272.204-.557.4-.844.579zM21.248 19.219l.217.17c.215-.273.418-.561.607-.854l-.23-.148c-.186.285-.385.564-.594.832zM19.855 20.715l.184.203c.258-.23.51-.479.746-.732l-.201-.188c-.23.248-.477.488-.729.717zM22.359 17.504l.244.129c.162-.307.314-.625.449-.945l-.254-.107a11.27 11.27 0 0 1-.439.923zM23.617 13.629l.273.039c.049-.346.082-.695.102-1.043l-.275-.014c-.018.338-.051.682-.1 1.018zM23.156 15.621l.264.086c.107-.332.201-.67.279-1.01l-.268-.063c-.077.333-.169.665-.275.987zM22.453 6.672c.154.303.297.617.424.932l.256-.104c-.131-.322-.277-.643-.436-.953l-.244.125zM8.296 23.418c.331.107.67.201 1.009.279l.062-.268c-.331-.076-.663-.168-.986-.273l-.085.262zM10.335 23.889c.345.049.696.082 1.043.102l.014-.275c-.339-.018-.682-.051-1.019-.098l-.038.271zM17.326 22.449c-.303.154-.613.297-.926.424l.104.256c.318-.131.639-.275.947-.434l.004-.002-.123-.246-.006.002zM4.613 21.467c.274.213.562.418.854.605l.149-.23c-.285-.184-.565-.385-.833-.592l-.17.217zM12.417 23.725l.009.275c.348-.014.699-.041 1.045-.084l-.035-.271c-.336.041-.68.068-1.019.08zM6.37 22.604c.307.162.625.314.946.449l.107-.254c-.313-.133-.624-.279-.924-.439l-.129.244zM3.083 20.041c.233.258.48.51.734.746l.188-.201c-.249-.23-.49-.477-.717-.729l-.205.184zM14.445 23.475l.059.27c.34-.074.68-.162 1.014-.266l-.082-.262c-.325.099-.659.185-.991.258zM21.18.129A2.689 2.689 0 1 0 21.18 5.507 2.689 2.689 0 1 0 21.18.129zM15.324 15.447c0 .471.314.66.852.66.67 0 1.297-.396 1.297-1.016v-.645c-.23.107-.379.141-1.107.24-.735.109-1.042.306-1.042.761zM12 2.818c-5.07 0-9.18 4.109-9.18 9.18 0 5.068 4.11 9.18 9.18 9.18 5.07 0 9.18-4.111 9.18-9.18 0-5.07-4.11-9.18-9.18-9.18zm-2.487 13.77H5.771v-6.023h.769v5.346h2.974v.677zm4.13 0h-.619v-.67c-.405.57-.811.793-1.446.793-.843 0-1.38-.463-1.38-1.182v-3.271h.686v3c0 .52.347.85.893.85.719 0 1.181-.578 1.181-1.461v-2.389h.686v4.33zm-.53-8.393c0-1.484 1.205-2.689 2.689-2.689s2.688 1.205 2.688 2.689-1.203 2.688-2.688 2.688-2.689-1.203-2.689-2.688zm5.567 7.856v.52c-.223.059-.33.074-.471.074-.34 0-.637-.238-.711-.57-.381.406-.918.637-1.471.637-.877 0-1.422-.463-1.422-1.248 0-.527.256-.916.76-1.123.266-.107.414-.141 1.389-.264.545-.066.719-.191.719-.48v-.182c0-.412-.348-.645-.967-.645-.645 0-.957.24-1.016.77h-.693c.041-1 .686-1.404 1.734-1.404 1.066 0 1.627.412 1.627 1.182v2.412c0 .215.133.338.373.338.041-.002.074-.002.149-.017z" />
65 </symbol>
66 <symbol id="t3-file-icon-php" viewBox="0 0 24 24">
67 <path style="fill: light-dark(#693acf, #9d6afb)" d="M7.01 10.207h-.944l-.515 2.648h.838c.556 0 .97-.105 1.242-.314.272-.21.455-.559.55-1.049.092-.47.05-.802-.124-.995-.175-.193-.523-.29-1.047-.29zM12 5.688C5.373 5.688 0 8.514 0 12s5.373 6.313 12 6.313S24 15.486 24 12c0-3.486-5.373-6.312-12-6.312zm-3.26 7.451c-.261.25-.575.438-.917.551-.336.108-.765.164-1.285.164H5.357l-.327 1.681H3.652l1.23-6.326h2.65c.797 0 1.378.209 1.744.628.366.418.476 1.002.33 1.752a2.836 2.836 0 0 1-.305.847c-.143.255-.33.49-.561.703zm4.024.715l.543-2.799c.063-.318.039-.536-.068-.651-.107-.116-.336-.174-.687-.174H11.46l-.704 3.625H9.388l1.23-6.327h1.367l-.327 1.682h1.218c.767 0 1.295.134 1.586.401s.378.7.263 1.299l-.572 2.944h-1.389zm7.597-2.265a2.782 2.782 0 0 1-.305.847c-.143.255-.33.49-.561.703a2.44 2.44 0 0 1-.917.551c-.336.108-.765.164-1.286.164h-1.18l-.327 1.682h-1.378l1.23-6.326h2.649c.797 0 1.378.209 1.744.628.366.417.477 1.001.331 1.751zM17.766 10.207h-.943l-.516 2.648h.838c.557 0 .971-.105 1.242-.314.272-.21.455-.559.551-1.049.092-.47.049-.802-.125-.995s-.524-.29-1.047-.29z" />
68 </symbol>
69 <symbol id="t3-file-icon-powershell" viewBox="0 0 24 24">
70 <path style="fill: light-dark(#1a85d4, #69b1ff)" d="M23.181 2.974c.568 0 .923.463.792 1.035l-3.659 15.982c-.13.572-.697 1.035-1.265 1.035H.819c-.568 0-.923-.463-.792-1.035L3.686 4.009c.13-.572.697-1.035 1.265-1.035zm-8.375 9.346c.251-.394.227-.905-.09-1.243L9.122 5.125c-.38-.404-1.037-.407-1.466-.003-.429.402-.468 1.056-.088 1.46l4.662 4.96v.11l-7.42 5.374c-.45.327-.533.977-.187 1.453.346.476.991.597 1.44.27l8.229-5.91c.28-.196.438-.365.514-.52zm-2.796 4.399a.928.928 0 00-.934.923c0 .51.418.923.934.923h4.433a.928.928 0 00.934-.923.928.928 0 00-.934-.923z" />
71 </symbol>
72 <symbol id="t3-file-icon-r" viewBox="0 0 24 24">
73 <path style="fill: light-dark(#1a85d4, #69b1ff)" d="M12 2.746c-6.627 0-12 3.599-12 8.037 0 3.897 4.144 7.144 9.64 7.88V16.26c-2.924-.915-4.925-2.755-4.925-4.877 0-3.035 4.084-5.494 9.12-5.494 5.038 0 8.757 1.683 8.757 5.494 0 1.976-.999 3.379-2.662 4.272.09.066.174.128.258.216.169.149.25.363.372.544 2.128-1.45 3.44-3.437 3.44-5.631 0-4.44-5.373-8.038-12-8.038zm-2.111 4.99v13.516l4.093-.002-.002-5.291h1.1c.225 0 .321.066.549.25.272.22.715.982.715.982l2.164 4.063 4.627-.002-2.864-4.826s-.086-.193-.265-.383a2.22 2.22 0 00-.582-.416c-.422-.214-1.149-.434-1.149-.434s3.578-.264 3.578-3.826c0-3.562-3.744-3.63-3.744-3.63zm4.127 2.93l2.478.002s1.149-.062 1.149 1.127c0 1.165-1.149 1.17-1.149 1.17h-2.478zm1.754 6.119c-.494.049-1.012.079-1.54.088v1.807a16.622 16.622 0 002.37-.473l-.471-.891s-.108-.183-.248-.394c-.039-.054-.08-.098-.111-.137z" />
74 </symbol>
75 <symbol id="t3-file-icon-scala" viewBox="0 0 24 24">
76 <path style="fill: light-dark(#d52c36, #ff6762)" d="M4.589 24c4.537 0 13.81-1.516 14.821-3v-5.729c-.957 1.408-10.284 2.912-14.821 2.912V24zM4.589 16.365c4.537 0 13.81-1.516 14.821-3V7.636c-.957 1.408-10.284 2.912-14.821 2.912v5.817zM4.589 8.729c4.537 0 13.81-1.516 14.821-3V0C18.453 1.408 9.126 2.912 4.589 2.912v5.817z" />
77 </symbol>
78 <symbol id="t3-file-icon-toml" viewBox="0 0 24 24">
79 <path style="fill: light-dark(#84848a, #adadb1)" d="M.014 0h5.34v2.652H2.888v18.681h2.468V24H.015V0Zm17.622 5.049v2.78h-4.274v12.935h-3.008V7.83H6.059V5.05h11.577ZM23.986 24h-5.34v-2.652h2.467V2.667h-2.468V0h5.34v24Z" />
80 </symbol>
81</svg>`;
82
83export const T3_PIERRE_ICONS = {
84 set: "complete",
85 colored: true,
86 spriteSheet: T3_FILE_ICON_SPRITE,
87 byFileName: {
88 "package.json": "file-tree-builtin-npm",
89 "tsconfig.json": "file-tree-builtin-typescript",
90 "agents.md": "t3-file-icon-agents",
91 "pnpm-lock.yaml": "t3-file-icon-pnpm",
92 "pnpm-workspace.yaml": "t3-file-icon-pnpm",
93 },
94 byFileExtension: {
95 ...Object.fromEntries(
96 VIDEO_FILE_EXTENSIONS.map((extension) => [extension, "t3-file-icon-video"]),
97 ),
98 // Languages the complete set has no icon for.
99 cs: "t3-file-icon-csharp",
100 csx: "t3-file-icon-csharp",
101 dart: "t3-file-icon-dart",
102 diff: "t3-file-icon-diff",
103 patch: "t3-file-icon-diff",
104 ex: "t3-file-icon-elixir",
105 exs: "t3-file-icon-elixir",
106 hs: "t3-file-icon-haskell",
107 lhs: "t3-file-icon-haskell",
108 java: "t3-file-icon-java",
109 kt: "t3-file-icon-kotlin",
110 kts: "t3-file-icon-kotlin",
111 lua: "t3-file-icon-lua",
112 php: "t3-file-icon-php",
113 ps1: "t3-file-icon-powershell",
114 psm1: "t3-file-icon-powershell",
115 psd1: "t3-file-icon-powershell",
116 r: "t3-file-icon-r",
117 scala: "t3-file-icon-scala",
118 toml: "t3-file-icon-toml",
119 xml: "t3-file-icon-xml",
120 },
121} satisfies FileTreeIcons;
122
123const completeIconResolver = createFileTreeIconResolver(T3_PIERRE_ICONS);
124
125const LANGUAGE_EXTENSION_ALIASES: Record<string, string> = {
126 bash: "sh",
127 csharp: "cs",
128 elixir: "ex",
129 haskell: "hs",
130 javascript: "js",
131 jsx: "jsx",
132 kotlin: "kt",
133 markdown: "md",
134 mdx: "mdx",
135 plaintext: "txt",
136 powershell: "ps1",
137 python: "py",
138 ruby: "rb",
139 rust: "rs",
140 shell: "sh",
141 shellscript: "sh",
142 swift: "swift",
143 typescript: "ts",
144 tsx: "tsx",
145 yaml: "yml",
146};
147
148export function basenameOfPath(pathValue: string): string {
149 const slashIndex = pathValue.lastIndexOf("/");
150 return slashIndex === -1 ? pathValue : pathValue.slice(slashIndex + 1);
151}
152
153/** Languages whose files are recognised by name rather than by extension. */
154const LANGUAGE_FILE_NAMES: Record<string, string> = {
155 dockerfile: "Dockerfile",
156};
157
158export function syntheticFileNameForLanguageId(languageId: string): string {
159 const normalized = languageId.toLowerCase();
160 return (
161 LANGUAGE_FILE_NAMES[normalized] ??
162 `file.${LANGUAGE_EXTENSION_ALIASES[normalized] ?? normalized}`
163 );
164}
165
166export function resolvePierreIconForEntry(
167 pathValue: string,
168 kind: "file" | "directory",
169 mimeType?: string,
170): PierreIconResolution | null {
171 if (kind === "directory") return null;
172 const icon = completeIconResolver.resolveIcon("file-tree-icon-file", pathValue);
173 return icon?.token === "default" && mimeType
174 ? completeIconResolver.resolveIcon(
175 "file-tree-icon-file",
176 fileIconPathForMimeType(pathValue, mimeType),
177 )
178 : icon;
179}
180
181export function hasSpecificPierreIconForFileName(fileName: string): boolean {
182 return resolvePierreIconForEntry(fileName, "file")?.token !== "default";
183}
184
185export function ensurePierreIconSprite(): void {
186 if (typeof document === "undefined" || document.getElementById(PIERRE_ICON_SPRITE_ID)) return;
187 const container = document.createElement("div");
188 container.id = PIERRE_ICON_SPRITE_ID;
189 container.setAttribute("aria-hidden", "true");
190 container.style.position = "absolute";
191 container.style.width = "0";
192 container.style.height = "0";
193 container.style.overflow = "hidden";
194 container.style.pointerEvents = "none";
195 container.innerHTML = `${getBuiltInSpriteSheet("complete")}${T3_FILE_ICON_SPRITE}`;
196 document.body.prepend(container);
197}