├── .editorconfig ├── .eslintrc.yaml ├── .gitattributes ├── .github └── workflows │ └── ci.yaml ├── .gitignore ├── .npmrc ├── LICENSE ├── Makefile ├── README.md ├── bin └── precompress.js ├── package-lock.json ├── package.json ├── precompress.js ├── precompress.test.js ├── snapshots └── precompress.test.js.snap ├── tsconfig.json ├── updates.config.js └── vitest.config.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | tab_width = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [Makefile] 13 | indent_style = tab 14 | -------------------------------------------------------------------------------- /.eslintrc.yaml: -------------------------------------------------------------------------------- 1 | root: true 2 | extends: silverwind 3 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | snapshots/*.snap linguist-language=JavaScript linguist-generated 3 | -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | name: ci 2 | on: [push, pull_request] 3 | 4 | jobs: 5 | test: 6 | strategy: 7 | fail-fast: false 8 | matrix: 9 | node: [18, 20, 22] 10 | os: [ubuntu-latest, macos-latest, windows-latest] 11 | 12 | runs-on: ${{matrix.os}} 13 | steps: 14 | - uses: actions/checkout@v4 15 | - uses: actions/setup-node@v4 16 | with: 17 | node-version: ${{matrix.node}} 18 | - run: make test 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.vscode 2 | /dist 3 | /node_modules 4 | /npm-debug.log* 5 | /yarn-error.log 6 | /yarn.lock 7 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | audit=false 2 | fund=false 3 | package-lock=true 4 | save-exact=true 5 | update-notifier=false 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) silverwind 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SRC := precompress.js 2 | DST := dist/precompress.js 3 | 4 | node_modules: package-lock.json 5 | npm install --no-save 6 | @touch node_modules 7 | 8 | .PHONY: deps 9 | deps: node_modules 10 | 11 | .PHONY: lint 12 | lint: node_modules 13 | npx eslint --color --quiet *.js 14 | 15 | .PHONY: lint-fix 16 | lint-fix: node_modules 17 | npx eslint --color --quiet *.js --fix 18 | 19 | .PHONY: test 20 | test: lint build node_modules 21 | npx vitest 22 | 23 | .PHONY: test 24 | test-update: build node_modules 25 | npx vitest --update 26 | 27 | .PHONY: build 28 | build: $(DST) 29 | 30 | $(DST): $(SRC) node_modules 31 | # workaround for https://github.com/evanw/esbuild/issues/1921 32 | npx esbuild --log-level=warning --platform=node --target=node18 --format=esm --bundle --minify --legal-comments=none --banner:js="import {createRequire} from 'module';const require = createRequire(import.meta.url);" --define:import.meta.VERSION=\"$(shell jq .version package.json)\" --outfile=$(DST) $(SRC) 33 | chmod +x $(DST) 34 | 35 | .PHONY: publish 36 | publish: 37 | git push -u --tags origin master 38 | npm publish 39 | 40 | .PHONY: update 41 | update: node_modules 42 | npx updates -cu 43 | rm -rf node_modules package-lock.json 44 | npm install 45 | @touch node_modules 46 | 47 | .PHONY: patch 48 | patch: node_modules test 49 | npx versions -c 'make --no-print-directory build' patch package.json package-lock.json 50 | @$(MAKE) --no-print-directory publish 51 | 52 | .PHONY: minor 53 | minor: node_modules test 54 | npx versions -c 'make --no-print-directory build' minor package.json package-lock.json 55 | @$(MAKE) --no-print-directory publish 56 | 57 | .PHONY: major 58 | major: node_modules test 59 | npx versions -c 'make --no-print-directory build' major package.json package-lock.json 60 | @$(MAKE) --no-print-directory publish 61 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # precompress 2 | [![](https://img.shields.io/npm/v/precompress.svg?style=flat)](https://www.npmjs.org/package/precompress) [![](https://img.shields.io/npm/dm/precompress.svg)](https://www.npmjs.org/package/precompress) [![](https://packagephobia.com/badge?p=precompress)](https://packagephobia.com/result?p=precompress) 3 | 4 | CLI to compress files to gzip and brotli. Files are efficiently compressed in parallel. Existing output files will always be overridden. 5 | 6 | ## Usage 7 | ```bash 8 | # compress all files in the "build" directory using node 9 | npx precompress ./build 10 | 11 | # same with bun 12 | bunx precompress ./build 13 | ``` 14 | 15 | ## Options 16 | ``` 17 | usage: precompress [options] 18 | 19 | Options: 20 | -t, --types Types of files to generate. Default: gz,br 21 | -i, --include Only include given globs. Default: unset 22 | -e, --exclude Exclude given globs. Default: **.gz,**.br 23 | -m, --mtime Skip creating existing files when source file is newer 24 | -f, --follow Follow symbolic links 25 | -d, --delete Delete source file after compression 26 | -o, --outdir Output directory, will preserve relative path structure 27 | -b, --basedir Base directory to derive output path, use with --outdir 28 | -E, --extensionless Do not output a extension, use with single --type and --outdir 29 | -s, --silent Do not print anything 30 | -S, --sensitive Treat include and exclude patterns case-sensitively 31 | -c, --concurrency Number of concurrent operations. Default: auto 32 | -V, --verbose Print individual file compression times 33 | -h, --help Show this text 34 | -v, --version Show the version 35 | 36 | Examples: 37 | $ precompress ./build 38 | ``` 39 | 40 | © [silverwind](https://github.com/silverwind), distributed under BSD licence 41 | -------------------------------------------------------------------------------- /bin/precompress.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import {createRequire} from 'module';const require = createRequire(import.meta.url); 3 | var Ye=Object.create;var Vt=Object.defineProperty;var Qe=Object.getOwnPropertyDescriptor;var We=Object.getOwnPropertyNames;var Ze=Object.getPrototypeOf,je=Object.prototype.hasOwnProperty;var zt=(t=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(t,{get:(n,e)=>(typeof require<"u"?require:n)[e]}):t)(function(t){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+t+'" is not supported')});var tt=(t,n)=>()=>(n||t((n={exports:{}}).exports,n),n.exports);var Je=(t,n,e,u)=>{if(n&&typeof n=="object"||typeof n=="function")for(let r of We(n))!je.call(t,r)&&r!==e&&Vt(t,r,{get:()=>n[r],enumerable:!(u=Qe(n,r))||u.enumerable});return t};var ht=(t,n,e)=>(e=t!=null?Ye(Ze(t)):{},Je(n||!t||!t.__esModule?Vt(e,"default",{value:t,enumerable:!0}):e,t));var Zt=tt((xr,Wt)=>{"use strict";function tn(t,n){var e=t;n.slice(0,-1).forEach(function(r){e=e[r]||{}});var u=n[n.length-1];return u in e}function Yt(t){return typeof t=="number"||/^0x[0-9a-f]+$/i.test(t)?!0:/^[-+]?(?:\d+(?:\.\d*)?|\.\d+)(e[-+]?\d+)?$/.test(t)}function Qt(t,n){return n==="constructor"&&typeof t[n]=="function"||n==="__proto__"}Wt.exports=function(t,n){n||(n={});var e={bools:{},strings:{},unknownFn:null};typeof n.unknown=="function"&&(e.unknownFn=n.unknown),typeof n.boolean=="boolean"&&n.boolean?e.allBools=!0:[].concat(n.boolean).filter(Boolean).forEach(function(d){e.bools[d]=!0});var u={};function r(d){return u[d].some(function(S){return e.bools[S]})}Object.keys(n.alias||{}).forEach(function(d){u[d]=[].concat(n.alias[d]),u[d].forEach(function(S){u[S]=[d].concat(u[d].filter(function(O){return S!==O}))})}),[].concat(n.string).filter(Boolean).forEach(function(d){e.strings[d]=!0,u[d]&&[].concat(u[d]).forEach(function(S){e.strings[S]=!0})});var l=n.default||{},a={_:[]};function p(d,S){return e.allBools&&/^--[^=]+$/.test(S)||e.strings[d]||e.bools[d]||u[d]}function b(d,S,O){for(var g=d,E=0;E{"use strict";var Q="\\\\/",Jt=`[^${Q}]`,j="\\.",en="\\+",nn="\\?",dt="\\/",rn="(?=.)",te="[^/]",gt=`(?:${dt}|$)`,ee=`(?:^|${dt})`,wt=`${j}{1,2}${gt}`,on=`(?!${j})`,sn=`(?!${ee}${wt})`,un=`(?!${j}{0,1}${gt})`,an=`(?!${wt})`,cn=`[^.${dt}]`,ln=`${te}*?`,fn="/",ne={DOT_LITERAL:j,PLUS_LITERAL:en,QMARK_LITERAL:nn,SLASH_LITERAL:dt,ONE_CHAR:rn,QMARK:te,END_ANCHOR:gt,DOTS_SLASH:wt,NO_DOT:on,NO_DOTS:sn,NO_DOT_SLASH:un,NO_DOTS_SLASH:an,QMARK_NO_DOT:cn,STAR:ln,START_ANCHOR:ee,SEP:fn},pn={...ne,SLASH_LITERAL:`[${Q}]`,QMARK:Jt,STAR:`${Jt}*?`,DOTS_SLASH:`${j}{1,2}(?:[${Q}]|$)`,NO_DOT:`(?!${j})`,NO_DOTS:`(?!(?:^|[${Q}])${j}{1,2}(?:[${Q}]|$))`,NO_DOT_SLASH:`(?!${j}{0,1}(?:[${Q}]|$))`,NO_DOTS_SLASH:`(?!${j}{1,2}(?:[${Q}]|$))`,QMARK_NO_DOT:`[^.${Q}]`,START_ANCHOR:`(?:^|[${Q}])`,END_ANCHOR:`(?:[${Q}]|$)`,SEP:"\\"},hn={alnum:"a-zA-Z0-9",alpha:"a-zA-Z",ascii:"\\x00-\\x7F",blank:" \\t",cntrl:"\\x00-\\x1F\\x7F",digit:"0-9",graph:"\\x21-\\x7E",lower:"a-z",print:"\\x20-\\x7E ",punct:"\\-!\"#$%&'()\\*+,./:;<=>?@[\\]^_`{|}~",space:" \\t\\r\\n\\v\\f",upper:"A-Z",word:"A-Za-z0-9_",xdigit:"A-Fa-f0-9"};re.exports={MAX_LENGTH:1024*64,POSIX_REGEX_SOURCE:hn,REGEX_BACKSLASH:/\\(?![*+?^${}(|)[\]])/g,REGEX_NON_SPECIAL_CHARS:/^[^@![\].,$*+?^{}()|\\/]+/,REGEX_SPECIAL_CHARS:/[-*+?.^${}(|)[\]]/,REGEX_SPECIAL_CHARS_BACKREF:/(\\?)((\W)(\3*))/g,REGEX_SPECIAL_CHARS_GLOBAL:/([-*+?.^${}(|)[\]])/g,REGEX_REMOVE_BACKSLASH:/(?:\[.*?[^\\]\]|\\(?=.))/g,REPLACEMENTS:{"***":"*","**/**":"**","**/**/**":"**"},CHAR_0:48,CHAR_9:57,CHAR_UPPERCASE_A:65,CHAR_LOWERCASE_A:97,CHAR_UPPERCASE_Z:90,CHAR_LOWERCASE_Z:122,CHAR_LEFT_PARENTHESES:40,CHAR_RIGHT_PARENTHESES:41,CHAR_ASTERISK:42,CHAR_AMPERSAND:38,CHAR_AT:64,CHAR_BACKWARD_SLASH:92,CHAR_CARRIAGE_RETURN:13,CHAR_CIRCUMFLEX_ACCENT:94,CHAR_COLON:58,CHAR_COMMA:44,CHAR_DOT:46,CHAR_DOUBLE_QUOTE:34,CHAR_EQUAL:61,CHAR_EXCLAMATION_MARK:33,CHAR_FORM_FEED:12,CHAR_FORWARD_SLASH:47,CHAR_GRAVE_ACCENT:96,CHAR_HASH:35,CHAR_HYPHEN_MINUS:45,CHAR_LEFT_ANGLE_BRACKET:60,CHAR_LEFT_CURLY_BRACE:123,CHAR_LEFT_SQUARE_BRACKET:91,CHAR_LINE_FEED:10,CHAR_NO_BREAK_SPACE:160,CHAR_PERCENT:37,CHAR_PLUS:43,CHAR_QUESTION_MARK:63,CHAR_RIGHT_ANGLE_BRACKET:62,CHAR_RIGHT_CURLY_BRACE:125,CHAR_RIGHT_SQUARE_BRACKET:93,CHAR_SEMICOLON:59,CHAR_SINGLE_QUOTE:39,CHAR_SPACE:32,CHAR_TAB:9,CHAR_UNDERSCORE:95,CHAR_VERTICAL_LINE:124,CHAR_ZERO_WIDTH_NOBREAK_SPACE:65279,extglobChars(t){return{"!":{type:"negate",open:"(?:(?!(?:",close:`))${t.STAR})`},"?":{type:"qmark",open:"(?:",close:")?"},"+":{type:"plus",open:"(?:",close:")+"},"*":{type:"star",open:"(?:",close:")*"},"@":{type:"at",open:"(?:",close:")"}}},globChars(t){return t===!0?pn:ne}}});var yt=tt(q=>{"use strict";var{REGEX_BACKSLASH:dn,REGEX_REMOVE_BACKSLASH:yn,REGEX_SPECIAL_CHARS:mn,REGEX_SPECIAL_CHARS_GLOBAL:An}=it();q.isObject=t=>t!==null&&typeof t=="object"&&!Array.isArray(t);q.hasRegexChars=t=>mn.test(t);q.isRegexChar=t=>t.length===1&&q.hasRegexChars(t);q.escapeRegex=t=>t.replace(An,"\\$1");q.toPosixSlashes=t=>t.replace(dn,"/");q.removeBackslashes=t=>t.replace(yn,n=>n==="\\"?"":n);q.escapeLast=(t,n,e)=>{let u=t.lastIndexOf(n,e);return u===-1?t:t[u-1]==="\\"?q.escapeLast(t,n,u-1):`${t.slice(0,u)}\\${t.slice(u)}`};q.removePrefix=(t,n={})=>{let e=t;return e.startsWith("./")&&(e=e.slice(2),n.prefix="./"),e};q.wrapOutput=(t,n={},e={})=>{let u=e.contains?"":"^",r=e.contains?"":"$",l=`${u}(?:${t})${r}`;return n.negated===!0&&(l=`(?:^(?!${l}).*$)`),l};q.basename=(t,{windows:n}={})=>{let e=t.split(n?/[\\/]/:"/"),u=e[e.length-1];return u===""?e[e.length-2]:u}});var fe=tt((Cr,le)=>{"use strict";var oe=yt(),{CHAR_ASTERISK:Ct,CHAR_AT:bn,CHAR_BACKWARD_SLASH:ut,CHAR_COMMA:En,CHAR_DOT:$t,CHAR_EXCLAMATION_MARK:Tt,CHAR_FORWARD_SLASH:ce,CHAR_LEFT_CURLY_BRACE:Ot,CHAR_LEFT_PARENTHESES:vt,CHAR_LEFT_SQUARE_BRACKET:_n,CHAR_PLUS:Rn,CHAR_QUESTION_MARK:se,CHAR_RIGHT_CURLY_BRACE:xn,CHAR_RIGHT_PARENTHESES:ie,CHAR_RIGHT_SQUARE_BRACKET:Sn}=it(),ue=t=>t===ce||t===ut,ae=t=>{t.isPrefix!==!0&&(t.depth=t.isGlobstar?1/0:1)},gn=(t,n)=>{let e=n||{},u=t.length-1,r=e.parts===!0||e.scanToEnd===!0,l=[],a=[],p=[],b=t,_=-1,y=0,m=0,h=!1,x=!1,R=!1,N=!1,U=!1,I=!1,w=!1,T=!1,d=!1,S=!1,O=0,g,E,A={value:"",depth:0,isGlob:!1},o=()=>_>=u,X=()=>b.charCodeAt(_+1),G=()=>(g=E,b.charCodeAt(++_));for(;_0&&(s=b.slice(0,y),b=b.slice(y),m-=y),F&&R===!0&&m>0?(F=b.slice(0,m),i=b.slice(m)):R===!0?(F="",i=b):F=b,F&&F!==""&&F!=="/"&&F!==b&&ue(F.charCodeAt(F.length-1))&&(F=F.slice(0,-1)),e.unescape===!0&&(i&&(i=oe.removeBackslashes(i)),F&&w===!0&&(F=oe.removeBackslashes(F)));let V={prefix:s,input:t,start:y,base:F,glob:i,isBrace:h,isBracket:x,isGlob:R,isExtglob:N,isGlobstar:U,negated:T,negatedExtglob:d};if(e.tokens===!0&&(V.maxDepth=0,ue(E)||a.push(A),V.tokens=a),e.parts===!0||e.tokens===!0){let v;for(let D=0;D{"use strict";var mt=it(),W=yt(),{MAX_LENGTH:At,POSIX_REGEX_SOURCE:wn,REGEX_NON_SPECIAL_CHARS:Cn,REGEX_SPECIAL_CHARS_BACKREF:$n,REPLACEMENTS:pe}=mt,Tn=(t,n)=>{if(typeof n.expandRange=="function")return n.expandRange(...t,n);t.sort();let e=`[${t.join("-")}]`;try{new RegExp(e)}catch{return t.map(r=>W.escapeRegex(r)).join("..")}return e},st=(t,n)=>`Missing ${t}: "${n}" - use "\\\\${n}" to match literal characters`,It=(t,n)=>{if(typeof t!="string")throw new TypeError("Expected a string");t=pe[t]||t;let e={...n},u=typeof e.maxLength=="number"?Math.min(At,e.maxLength):At,r=t.length;if(r>u)throw new SyntaxError(`Input length: ${r}, exceeds maximum allowed length: ${u}`);let l={type:"bos",value:"",output:e.prepend||""},a=[l],p=e.capture?"":"?:",b=mt.globChars(e.windows),_=mt.extglobChars(b),{DOT_LITERAL:y,PLUS_LITERAL:m,SLASH_LITERAL:h,ONE_CHAR:x,DOTS_SLASH:R,NO_DOT:N,NO_DOT_SLASH:U,NO_DOTS_SLASH:I,QMARK:w,QMARK_NO_DOT:T,STAR:d,START_ANCHOR:S}=b,O=f=>`(${p}(?:(?!${S}${f.dot?R:y}).)*?)`,g=e.dot?"":N,E=e.dot?w:T,A=e.bash===!0?O(e):d;e.capture&&(A=`(${A})`),typeof e.noext=="boolean"&&(e.noextglob=e.noext);let o={input:t,index:-1,start:0,dot:e.dot===!0,consumed:"",output:"",prefix:"",backtrack:!1,negated:!1,brackets:0,braces:0,parens:0,quotes:0,globstar:!1,tokens:a};t=W.removePrefix(t,o),r=t.length;let X=[],G=[],F=[],s=l,i,V=()=>o.index===r-1,v=o.peek=(f=1)=>t[o.index+f],D=o.advance=()=>t[++o.index]||"",Z=()=>t.slice(o.index+1),z=(f="",H=0)=>{o.consumed+=f,o.index+=H},J=f=>{o.output+=f.output!=null?f.output:f.value,z(f.value)},Ve=()=>{let f=1;for(;v()==="!"&&(v(2)!=="("||v(3)==="?");)D(),o.start++,f++;return f%2===0?!1:(o.negated=!0,o.start++,!0)},lt=f=>{o[f]++,F.push(f)},rt=f=>{o[f]--,F.pop()},$=f=>{if(s.type==="globstar"){let H=o.braces>0&&(f.type==="comma"||f.type==="brace"),c=f.extglob===!0||X.length&&(f.type==="pipe"||f.type==="paren");f.type!=="slash"&&f.type!=="paren"&&!H&&!c&&(o.output=o.output.slice(0,-s.output.length),s.type="star",s.value="*",s.output=A,o.output+=s.output)}if(X.length&&f.type!=="paren"&&(X[X.length-1].inner+=f.value),(f.value||f.output)&&J(f),s&&s.type==="text"&&f.type==="text"){s.output=(s.output||s.value)+f.value,s.value+=f.value;return}f.prev=s,a.push(f),s=f},ft=(f,H)=>{let c={..._[H],conditions:1,inner:""};c.prev=s,c.parens=o.parens,c.output=o.output;let C=(e.capture?"(":"")+c.open;lt("parens"),$({type:f,value:H,output:o.output?"":x}),$({type:"paren",extglob:!0,value:D(),output:C}),X.push(c)},ze=f=>{let H=f.close+(e.capture?")":""),c;if(f.type==="negate"){let C=A;if(f.inner&&f.inner.length>1&&f.inner.includes("/")&&(C=O(e)),(C!==A||V()||/^\)+$/.test(Z()))&&(H=f.close=`)$))${C}`),f.inner.includes("*")&&(c=Z())&&/^\.[^\\/.]+$/.test(c)){let P=It(c,{...n,fastpaths:!1}).output;H=f.close=`)${P})${C})`}f.prev.type==="bos"&&(o.negatedExtglob=!0)}$({type:"paren",extglob:!0,value:i,output:H}),rt("parens")};if(e.fastpaths!==!1&&!/(^[*!]|[/()[\]{}"])/.test(t)){let f=!1,H=t.replace($n,(c,C,P,K,k,xt)=>K==="\\"?(f=!0,c):K==="?"?C?C+K+(k?w.repeat(k.length):""):xt===0?E+(k?w.repeat(k.length):""):w.repeat(P.length):K==="."?y.repeat(P.length):K==="*"?C?C+K+(k?A:""):A:C?c:`\\${c}`);return f===!0&&(e.unescape===!0?H=H.replace(/\\/g,""):H=H.replace(/\\+/g,c=>c.length%2===0?"\\\\":c?"\\":"")),H===t&&e.contains===!0?(o.output=t,o):(o.output=W.wrapOutput(H,o,n),o)}for(;!V();){if(i=D(),i==="\0")continue;if(i==="\\"){let c=v();if(c==="/"&&e.bash!==!0||c==="."||c===";")continue;if(!c){i+="\\",$({type:"text",value:i});continue}let C=/^\\+/.exec(Z()),P=0;if(C&&C[0].length>2&&(P=C[0].length,o.index+=P,P%2!==0&&(i+="\\")),e.unescape===!0?i=D():i+=D(),o.brackets===0){$({type:"text",value:i});continue}}if(o.brackets>0&&(i!=="]"||s.value==="["||s.value==="[^")){if(e.posix!==!1&&i===":"){let c=s.value.slice(1);if(c.includes("[")&&(s.posix=!0,c.includes(":"))){let C=s.value.lastIndexOf("["),P=s.value.slice(0,C),K=s.value.slice(C+2),k=wn[K];if(k){s.value=P+k,o.backtrack=!0,D(),!l.output&&a.indexOf(s)===1&&(l.output=x);continue}}}(i==="["&&v()!==":"||i==="-"&&v()==="]")&&(i=`\\${i}`),i==="]"&&(s.value==="["||s.value==="[^")&&(i=`\\${i}`),e.posix===!0&&i==="!"&&s.value==="["&&(i="^"),s.value+=i,J({value:i});continue}if(o.quotes===1&&i!=='"'){i=W.escapeRegex(i),s.value+=i,J({value:i});continue}if(i==='"'){o.quotes=o.quotes===1?0:1,e.keepQuotes===!0&&$({type:"text",value:i});continue}if(i==="("){lt("parens"),$({type:"paren",value:i});continue}if(i===")"){if(o.parens===0&&e.strictBrackets===!0)throw new SyntaxError(st("opening","("));let c=X[X.length-1];if(c&&o.parens===c.parens+1){ze(X.pop());continue}$({type:"paren",value:i,output:o.parens?")":"\\)"}),rt("parens");continue}if(i==="["){if(e.nobracket===!0||!Z().includes("]")){if(e.nobracket!==!0&&e.strictBrackets===!0)throw new SyntaxError(st("closing","]"));i=`\\${i}`}else lt("brackets");$({type:"bracket",value:i});continue}if(i==="]"){if(e.nobracket===!0||s&&s.type==="bracket"&&s.value.length===1){$({type:"text",value:i,output:`\\${i}`});continue}if(o.brackets===0){if(e.strictBrackets===!0)throw new SyntaxError(st("opening","["));$({type:"text",value:i,output:`\\${i}`});continue}rt("brackets");let c=s.value.slice(1);if(s.posix!==!0&&c[0]==="^"&&!c.includes("/")&&(i=`/${i}`),s.value+=i,J({value:i}),e.literalBrackets===!1||W.hasRegexChars(c))continue;let C=W.escapeRegex(s.value);if(o.output=o.output.slice(0,-s.value.length),e.literalBrackets===!0){o.output+=C,s.value=C;continue}s.value=`(${p}${C}|${s.value})`,o.output+=s.value;continue}if(i==="{"&&e.nobrace!==!0){lt("braces");let c={type:"brace",value:i,output:"(",outputIndex:o.output.length,tokensIndex:o.tokens.length};G.push(c),$(c);continue}if(i==="}"){let c=G[G.length-1];if(e.nobrace===!0||!c){$({type:"text",value:i,output:i});continue}let C=")";if(c.dots===!0){let P=a.slice(),K=[];for(let k=P.length-1;k>=0&&(a.pop(),P[k].type!=="brace");k--)P[k].type!=="dots"&&K.unshift(P[k].value);C=Tn(K,e),o.backtrack=!0}if(c.comma!==!0&&c.dots!==!0){let P=o.output.slice(0,c.outputIndex),K=o.tokens.slice(c.tokensIndex);c.value=c.output="\\{",i=C="\\}",o.output=P;for(let k of K)o.output+=k.output||k.value}$({type:"brace",value:i,output:C}),rt("braces"),G.pop();continue}if(i==="|"){X.length>0&&X[X.length-1].conditions++,$({type:"text",value:i});continue}if(i===","){let c=i,C=G[G.length-1];C&&F[F.length-1]==="braces"&&(C.comma=!0,c="|"),$({type:"comma",value:i,output:c});continue}if(i==="/"){if(s.type==="dot"&&o.index===o.start+1){o.start=o.index+1,o.consumed="",o.output="",a.pop(),s=l;continue}$({type:"slash",value:i,output:h});continue}if(i==="."){if(o.braces>0&&s.type==="dot"){s.value==="."&&(s.output=y);let c=G[G.length-1];s.type="dots",s.output+=i,s.value+=i,c.dots=!0;continue}if(o.braces+o.parens===0&&s.type!=="bos"&&s.type!=="slash"){$({type:"text",value:i,output:y});continue}$({type:"dot",value:i,output:y});continue}if(i==="?"){if(!(s&&s.value==="(")&&e.noextglob!==!0&&v()==="("&&v(2)!=="?"){ft("qmark",i);continue}if(s&&s.type==="paren"){let C=v(),P=i;(s.value==="("&&!/[!=<:]/.test(C)||C==="<"&&!/<([!=]|\w+>)/.test(Z()))&&(P=`\\${i}`),$({type:"text",value:i,output:P});continue}if(e.dot!==!0&&(s.type==="slash"||s.type==="bos")){$({type:"qmark",value:i,output:T});continue}$({type:"qmark",value:i,output:w});continue}if(i==="!"){if(e.noextglob!==!0&&v()==="("&&(v(2)!=="?"||!/[!=<:]/.test(v(3)))){ft("negate",i);continue}if(e.nonegate!==!0&&o.index===0){Ve();continue}}if(i==="+"){if(e.noextglob!==!0&&v()==="("&&v(2)!=="?"){ft("plus",i);continue}if(s&&s.value==="("||e.regex===!1){$({type:"plus",value:i,output:m});continue}if(s&&(s.type==="bracket"||s.type==="paren"||s.type==="brace")||o.parens>0){$({type:"plus",value:i});continue}$({type:"plus",value:m});continue}if(i==="@"){if(e.noextglob!==!0&&v()==="("&&v(2)!=="?"){$({type:"at",extglob:!0,value:i,output:""});continue}$({type:"text",value:i});continue}if(i!=="*"){(i==="$"||i==="^")&&(i=`\\${i}`);let c=Cn.exec(Z());c&&(i+=c[0],o.index+=c[0].length),$({type:"text",value:i});continue}if(s&&(s.type==="globstar"||s.star===!0)){s.type="star",s.star=!0,s.value+=i,s.output=A,o.backtrack=!0,o.globstar=!0,z(i);continue}let f=Z();if(e.noextglob!==!0&&/^\([^?]/.test(f)){ft("star",i);continue}if(s.type==="star"){if(e.noglobstar===!0){z(i);continue}let c=s.prev,C=c.prev,P=c.type==="slash"||c.type==="bos",K=C&&(C.type==="star"||C.type==="globstar");if(e.bash===!0&&(!P||f[0]&&f[0]!=="/")){$({type:"star",value:i,output:""});continue}let k=o.braces>0&&(c.type==="comma"||c.type==="brace"),xt=X.length&&(c.type==="pipe"||c.type==="paren");if(!P&&c.type!=="paren"&&!k&&!xt){$({type:"star",value:i,output:""});continue}for(;f.slice(0,3)==="/**";){let pt=t[o.index+4];if(pt&&pt!=="/")break;f=f.slice(3),z("/**",3)}if(c.type==="bos"&&V()){s.type="globstar",s.value+=i,s.output=O(e),o.output=s.output,o.globstar=!0,z(i);continue}if(c.type==="slash"&&c.prev.type!=="bos"&&!K&&V()){o.output=o.output.slice(0,-(c.output+s.output).length),c.output=`(?:${c.output}`,s.type="globstar",s.output=O(e)+(e.strictSlashes?")":"|$)"),s.value+=i,o.globstar=!0,o.output+=c.output+s.output,z(i);continue}if(c.type==="slash"&&c.prev.type!=="bos"&&f[0]==="/"){let pt=f[1]!==void 0?"|$":"";o.output=o.output.slice(0,-(c.output+s.output).length),c.output=`(?:${c.output}`,s.type="globstar",s.output=`${O(e)}${h}|${h}${pt})`,s.value+=i,o.output+=c.output+s.output,o.globstar=!0,z(i+D()),$({type:"slash",value:"/",output:""});continue}if(c.type==="bos"&&f[0]==="/"){s.type="globstar",s.value+=i,s.output=`(?:^|${h}|${O(e)}${h})`,o.output=s.output,o.globstar=!0,z(i+D()),$({type:"slash",value:"/",output:""});continue}o.output=o.output.slice(0,-s.output.length),s.type="globstar",s.output=O(e),s.value+=i,o.output+=s.output,o.globstar=!0,z(i);continue}let H={type:"star",value:i,output:A};if(e.bash===!0){H.output=".*?",(s.type==="bos"||s.type==="slash")&&(H.output=g+H.output),$(H);continue}if(s&&(s.type==="bracket"||s.type==="paren")&&e.regex===!0){H.output=i,$(H);continue}(o.index===o.start||s.type==="slash"||s.type==="dot")&&(s.type==="dot"?(o.output+=U,s.output+=U):e.dot===!0?(o.output+=I,s.output+=I):(o.output+=g,s.output+=g),v()!=="*"&&(o.output+=x,s.output+=x)),$(H)}for(;o.brackets>0;){if(e.strictBrackets===!0)throw new SyntaxError(st("closing","]"));o.output=W.escapeLast(o.output,"["),rt("brackets")}for(;o.parens>0;){if(e.strictBrackets===!0)throw new SyntaxError(st("closing",")"));o.output=W.escapeLast(o.output,"("),rt("parens")}for(;o.braces>0;){if(e.strictBrackets===!0)throw new SyntaxError(st("closing","}"));o.output=W.escapeLast(o.output,"{"),rt("braces")}if(e.strictSlashes!==!0&&(s.type==="star"||s.type==="bracket")&&$({type:"maybe_slash",value:"",output:`${h}?`}),o.backtrack===!0){o.output="";for(let f of o.tokens)o.output+=f.output!=null?f.output:f.value,f.suffix&&(o.output+=f.suffix)}return o};It.fastpaths=(t,n)=>{let e={...n},u=typeof e.maxLength=="number"?Math.min(At,e.maxLength):At,r=t.length;if(r>u)throw new SyntaxError(`Input length: ${r}, exceeds maximum allowed length: ${u}`);t=pe[t]||t;let{DOT_LITERAL:l,SLASH_LITERAL:a,ONE_CHAR:p,DOTS_SLASH:b,NO_DOT:_,NO_DOTS:y,NO_DOTS_SLASH:m,STAR:h,START_ANCHOR:x}=mt.globChars(e.windows),R=e.dot?y:_,N=e.dot?m:_,U=e.capture?"":"?:",I={negated:!1,prefix:""},w=e.bash===!0?".*?":h;e.capture&&(w=`(${w})`);let T=g=>g.noglobstar===!0?w:`(${U}(?:(?!${x}${g.dot?b:l}).)*?)`,d=g=>{switch(g){case"*":return`${R}${p}${w}`;case".*":return`${l}${p}${w}`;case"*.*":return`${R}${w}${l}${p}${w}`;case"*/*":return`${R}${w}${a}${p}${N}${w}`;case"**":return R+T(e);case"**/*":return`(?:${R}${T(e)}${a})?${N}${p}${w}`;case"**/*.*":return`(?:${R}${T(e)}${a})?${N}${w}${l}${p}${w}`;case"**/.*":return`(?:${R}${T(e)}${a})?${l}${p}${w}`;default:{let E=/^(.*?)\.(\w+)$/.exec(g);if(!E)return;let A=d(E[1]);return A?A+l+E[2]:void 0}}},S=W.removePrefix(t,I),O=d(S);return O&&e.strictSlashes!==!0&&(O+=`${a}?`),O};he.exports=It});var Ae=tt((Tr,me)=>{"use strict";var On=fe(),Lt=de(),ye=yt(),vn=it(),In=t=>t&&typeof t=="object"&&!Array.isArray(t),B=(t,n,e=!1)=>{if(Array.isArray(t)){let y=t.map(h=>B(h,n,e));return h=>{for(let x of y){let R=x(h);if(R)return R}return!1}}let u=In(t)&&t.tokens&&t.input;if(t===""||typeof t!="string"&&!u)throw new TypeError("Expected pattern to be a non-empty string");let r=n||{},l=r.windows,a=u?B.compileRe(t,n):B.makeRe(t,n,!1,!0),p=a.state;delete a.state;let b=()=>!1;if(r.ignore){let y={...n,ignore:null,onMatch:null,onResult:null};b=B(r.ignore,y,e)}let _=(y,m=!1)=>{let{isMatch:h,match:x,output:R}=B.test(y,a,n,{glob:t,posix:l}),N={glob:t,state:p,regex:a,posix:l,input:y,output:R,match:x,isMatch:h};return typeof r.onResult=="function"&&r.onResult(N),h===!1?(N.isMatch=!1,m?N:!1):b(y)?(typeof r.onIgnore=="function"&&r.onIgnore(N),N.isMatch=!1,m?N:!1):(typeof r.onMatch=="function"&&r.onMatch(N),m?N:!0)};return e&&(_.state=p),_};B.test=(t,n,e,{glob:u,posix:r}={})=>{if(typeof t!="string")throw new TypeError("Expected input to be a string");if(t==="")return{isMatch:!1,output:""};let l=e||{},a=l.format||(r?ye.toPosixSlashes:null),p=t===u,b=p&&a?a(t):t;return p===!1&&(b=a?a(t):t,p=b===u),(p===!1||l.capture===!0)&&(l.matchBase===!0||l.basename===!0?p=B.matchBase(t,n,e,r):p=n.exec(b)),{isMatch:!!p,match:p,output:b}};B.matchBase=(t,n,e)=>(n instanceof RegExp?n:B.makeRe(n,e)).test(ye.basename(t));B.isMatch=(t,n,e)=>B(n,e)(t);B.parse=(t,n)=>Array.isArray(t)?t.map(e=>B.parse(e,n)):Lt(t,{...n,fastpaths:!1});B.scan=(t,n)=>On(t,n);B.compileRe=(t,n,e=!1,u=!1)=>{if(e===!0)return t.output;let r=n||{},l=r.contains?"":"^",a=r.contains?"":"$",p=`${l}(?:${t.output})${a}`;t&&t.negated===!0&&(p=`^(?!${p}).*$`);let b=B.toRegex(p,n);return u===!0&&(b.state=t),b};B.makeRe=(t,n={},e=!1,u=!1)=>{if(!t||typeof t!="string")throw new TypeError("Expected a non-empty string");let r={negated:!1,fastpaths:!0};return n.fastpaths!==!1&&(t[0]==="."||t[0]==="*")&&(r.output=Lt.fastpaths(t,n)),r.output||(r=Lt(t,n)),B.compileRe(r,n,e,u)};B.toRegex=(t,n)=>{try{let e=n||{};return new RegExp(t,e.flags||(e.nocase?"i":""))}catch(e){if(n&&n.debug===!0)throw e;return/$^/}};B.constants=vn;me.exports=B});var Ht=tt((Or,_e)=>{"use strict";var be=Ae(),Ln=()=>{if(typeof navigator<"u"&&navigator.platform){let t=navigator.platform.toLowerCase();return t==="win32"||t==="windows"}return typeof process<"u"&&process.platform?process.platform==="win32":!1};function Ee(t,n,e=!1){return n&&(n.windows===null||n.windows===void 0)&&(n={...n,windows:Ln()}),be(t,n,e)}Object.assign(Ee,be);_e.exports=Ee});var Oe=tt(nt=>{"use strict";var kn=nt&&nt.__awaiter||function(t,n,e,u){function r(l){return l instanceof e?l:new e(function(a){a(l)})}return new(e||(e=Promise))(function(l,a){function p(y){try{_(u.next(y))}catch(m){a(m)}}function b(y){try{_(u.throw(y))}catch(m){a(m)}}function _(y){y.done?l(y.value):r(y.value).then(p,b)}_((u=u.apply(t,n||[])).next())})};Object.defineProperty(nt,"__esModule",{value:!0});nt.isBinaryFileSync=nt.isBinaryFile=void 0;var et=zt("fs"),Ft=zt("util"),Un=(0,Ft.promisify)(et.stat),Kn=(0,Ft.promisify)(et.open),Xn=(0,Ft.promisify)(et.close),at=512,Mt=class{constructor(n,e){this.fileBuffer=n,this.size=e,this.offset=0,this.error=!1}hasError(){return this.error}nextByte(){return this.offset===this.size||this.hasError()?(this.error=!0,255):this.fileBuffer[this.offset++]}next(n){let e=new Array;for(let u=0;u0}function zn(t,n){return kn(this,void 0,void 0,function*(){if($e(t)){let e=yield Un(t);Te(e);let u=yield Kn(t,"r"),r=Buffer.alloc(at);return new Promise((l,a)=>{et.read(u,r,0,at,0,(p,b,_)=>{Xn(u),p?a(p):l(bt(r,b))})})}else return n===void 0&&(n=t.length),bt(t,n)})}nt.isBinaryFile=zn;function Yn(t,n){if($e(t)){let e=et.statSync(t);Te(e);let u=et.openSync(t,"r"),r=Buffer.alloc(at),l=et.readSync(u,r,0,at,0);return et.closeSync(u),bt(r,l)}else return n===void 0&&(n=t.length),bt(t,n)}nt.isBinaryFileSync=Yn;function bt(t,n){if(n===0)return!1;let e=0,u=Math.min(n,at);if(n>=3&&t[0]===239&&t[1]===187&&t[2]===191||n>=4&&t[0]===0&&t[1]===0&&t[2]===254&&t[3]===255||n>=4&&t[0]===255&&t[1]===254&&t[2]===0&&t[3]===0||n>=4&&t[0]===132&&t[1]===49&&t[2]===149&&t[3]===51)return!1;if(u>=5&&t.slice(0,5).toString()==="%PDF-")return!0;if(n>=2&&t[0]===254&&t[1]===255||n>=2&&t[0]===255&&t[1]===254)return!1;for(let r=0;r14)&&(t[r]<32||t[r]>127)){if(t[r]>193&&t[r]<224&&r+1127&&t[r]<192)continue}else if(t[r]>223&&t[r]<240&&r+2127&&t[r]<192&&t[r+1]>127&&t[r+1]<192)){r++;continue}if(e++,r>=32&&e*100/u>10)return!0}}return!!(e*100/u>10||e>1&&Vn(t,u))}function $e(t){return typeof t=="string"}function Te(t){if(!t.isFile())throw new Error("Path provided was not a file!")}});var ke=ht(Zt(),1);async function St(t,n,{concurrency:e=Number.POSITIVE_INFINITY,stopOnError:u=!0,signal:r}={}){return new Promise((l,a)=>{if(t[Symbol.iterator]===void 0&&t[Symbol.asyncIterator]===void 0)throw new TypeError(`Expected \`input\` to be either an \`Iterable\` or \`AsyncIterable\`, got (${typeof t})`);if(typeof n!="function")throw new TypeError("Mapper function is required");if(!(Number.isSafeInteger(e)&&e>=1||e===Number.POSITIVE_INFINITY))throw new TypeError(`Expected \`concurrency\` to be an integer from 1 and up or \`Infinity\`, got \`${e}\` (${typeof e})`);let p=[],b=[],_=new Map,y=!1,m=!1,h=!1,x=0,R=0,N=t[Symbol.iterator]===void 0?t[Symbol.asyncIterator]():t[Symbol.iterator](),U=w=>{y=!0,m=!0,a(w)};r&&(r.aborted&&U(r.reason),r.addEventListener("abort",()=>{U(r.reason)}));let I=async()=>{if(m)return;let w=await N.next(),T=R;if(R++,w.done){if(h=!0,x===0&&!m){if(!u&&b.length>0){U(new AggregateError(b));return}if(m=!0,_.size===0){l(p);return}let d=[];for(let[S,O]of p.entries())_.get(S)!==jt&&d.push(O);l(d)}return}x++,(async()=>{try{let d=await w.value;if(m)return;let S=await n(d,T);S===jt&&_.set(T,S),p[T]=S,x--,await I()}catch(d){if(u)U(d);else{b.push(d),x--;try{await I()}catch(S){U(S)}}}})()};(async()=>{for(let w=0;w(0,Nt.default)(t,u)(xe(r)):null,excludeMatcher:n?.length?r=>(0,Nt.default)(n,u)(xe(r)):null}}async function*Dt(t,n={},{includeMatcher:e,excludeMatcher:u,encoding:r}={}){e===void 0&&(n={...Mn,...n},{includeMatcher:e,excludeMatcher:u}=Gn(n),/[/\\]$/.test(t)&&(t=t.substring(0,t.length-1)),r=t instanceof Uint8Array?"buffer":void 0);let l=[];try{l=await Hn(t,{encoding:r,withFileTypes:!0})}catch(a){if(n.strict)throw a;yield{path:t,err:a}}if(l.length)for(let a of l){let p=Fn(a,t,r);if(u?.(r==="buffer"?we(p):p))continue;let b=n.followSymlinks&&a.isSymbolicLink(),_=r==="buffer"?we(p):p,y=!e||e(_),m;if(y){if(n.stats||b)try{m=await(n.followSymlinks?Re:Nn)(p)}catch(x){if(n.strict)throw x;yield{path:p,err:x}}yield Bn(a,p,m,n)}let h=!1;if(b){if(!m)try{m=await Re(p)}catch{}m&&m.isDirectory()&&(h=!0)}else a.isDirectory()&&(h=!0);h&&(yield*await Dt(p,n,{includeMatcher:e,excludeMatcher:u,encoding:r}))}}var Ke=ht(Oe(),1);import{constants as ot,gzip as tr,brotliCompress as er}from"node:zlib";import Fe from"node:os";import{argv as nr,exit as rr,versions as or}from"node:process";import{promisify as Ue}from"node:util";import{stat as ct,readFile as sr,writeFile as ir,realpath as ur,mkdir as ar,unlink as cr}from"node:fs/promises";import{extname as lr,relative as fr,join as pr,dirname as hr}from"node:path";import{readFileSync as dr}from"node:fs";import Bt from"node:process";import Qn from"node:os";import ve from"node:tty";function Y(t,n=globalThis.Deno?globalThis.Deno.args:Bt.argv){let e=t.startsWith("-")?"":t.length===1?"-":"--",u=n.indexOf(e+t),r=n.indexOf("--");return u!==-1&&(r===-1||u=2,has16m:t>=3}}function jn(t,{streamIsTTY:n,sniffFlags:e=!0}={}){let u=Wn();u!==void 0&&(Et=u);let r=e?Et:u;if(r===0)return 0;if(e){if(Y("color=16m")||Y("color=full")||Y("color=truecolor"))return 3;if(Y("color=256"))return 2}if("TF_BUILD"in M&&"AGENT_NAME"in M)return 1;if(t&&!n&&r===void 0)return 0;let l=r||0;if(M.TERM==="dumb")return l;if(Bt.platform==="win32"){let a=Qn.release().split(".");return Number(a[0])>=10&&Number(a[2])>=10586?Number(a[2])>=14931?3:2:1}if("CI"in M)return"GITHUB_ACTIONS"in M||"GITEA_ACTIONS"in M?3:["TRAVIS","CIRCLECI","APPVEYOR","GITLAB_CI","BUILDKITE","DRONE"].some(a=>a in M)||M.CI_NAME==="codeship"?1:l;if("TEAMCITY_VERSION"in M)return/^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(M.TEAMCITY_VERSION)?1:0;if(M.COLORTERM==="truecolor"||M.TERM==="xterm-kitty")return 3;if("TERM_PROGRAM"in M){let a=Number.parseInt((M.TERM_PROGRAM_VERSION||"").split(".")[0],10);switch(M.TERM_PROGRAM){case"iTerm.app":return a>=3?3:2;case"Apple_Terminal":return 2}}return/-256(color)?$/i.test(M.TERM)?2:/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(M.TERM)||"COLORTERM"in M?1:l}function Ie(t,n={}){let e=jn(t,{streamIsTTY:t&&t.isTTY,...n});return Zn(e)}var Jn={stdout:Ie({isTTY:ve.isatty(1)}),stderr:Ie({isTTY:ve.isatty(2)})},Le=Jn;var He=!0;function Ne(){He=!1}function _t(t,n,e){return He?`\x1B[${n}m${t.join(" ")}\x1B[${e}m`:t.join(" ")}var De=(...t)=>_t(t,31,39),Gt=(...t)=>_t(t,32,39),Pe=(...t)=>_t(t,33,39);var Me=(...t)=>_t(t,35,39);var kt=ht(Ht(),1),Xe=["**.gz","**.br"],Ut=Fe.availableParallelism?.()??Fe.cpus().length??4;or?.uv&&Ut>4&&(process.env.UV_THREADPOOL_SIZE=String(Ut));var L=(0,ke.default)(nr.slice(2),{boolean:["d","delete","E","extensionless","f","follow","h","help","m","mtime","s","silent","S","sensitive","v","version","V","verbose"],string:["b","basedir","o","outdir","t","types","_"],number:["c","concurrency"],alias:{b:"basedir",c:"concurrency",d:"delete",e:"exclude",E:"extensionless",h:"help",i:"include",o:"outdir",m:"mtime",s:"silent",S:"sensitive",t:"types",v:"version",V:"verbose"}});Le.stdout||Ne();function Rt(t){t&&console.error(t.stack||t.message||t),rr(t?1:0)}var Kt="12.0.3";Kt||(Kt=JSON.parse(dr(new URL("package.json",import.meta.url))).version);L.version&&(console.info("12.0.3"),Rt());(!L._.length||L.help)&&(console.info(`usage: precompress [options] 4 | 5 | Options: 6 | -t, --types Types of files to generate. Default: gz,br 7 | -i, --include Only include given globs. Default: unset 8 | -e, --exclude Exclude given globs. Default: ${Xe} 9 | -m, --mtime Skip creating existing files when source file is newer 10 | -f, --follow Follow symbolic links 11 | -d, --delete Delete source file after compression 12 | -o, --outdir Output directory, will preserve relative path structure 13 | -b, --basedir Base directory to derive output path, use with --outdir 14 | -E, --extensionless Do not output a extension, use with single --type and --outdir 15 | -s, --silent Do not print anything 16 | -S, --sensitive Treat include and exclude patterns case-sensitively 17 | -c, --concurrency Number of concurrent operations. Default: auto 18 | -V, --verbose Print individual file compression times 19 | -h, --help Show this text 20 | -v, --version Show the version 21 | 22 | Examples: 23 | $ precompress ./build`),Rt());function yr(t,n){return lr(n).toLowerCase()===".woff2"?ot.BROTLI_MODE_FONT:(0,Ke.isBinaryFileSync)(t)?ot.BROTLI_MODE_GENERIC:ot.BROTLI_MODE_TEXT}function mr(t,n){let e=(n.byteLength/t.byteLength*100).toPrecision(3);return e<=80?`(${Gt(`${e}%`)} size)`:e<100?`(${Pe(`${e}%`)} size)`:`(${De(`${e}%`)} size)`}var qe=L.types?L.types.split(","):["gz","br"],Xt=qe.includes("gz")&&((t,n)=>Ue(tr)(t,{level:ot.Z_BEST_COMPRESSION})),qt=qe.includes("br")&&((t,n)=>Ue(er)(t,{params:{[ot.BROTLI_PARAM_MODE]:yr(t,n),[ot.BROTLI_PARAM_QUALITY]:ot.BROTLI_MAX_QUALITY}}));function Be(t){return typeof t=="boolean"||!t?[]:(Array.isArray(t)?t:[t]).flatMap(n=>n.split(",")).filter(Boolean)}function Ar(t,n){let e=L.basedir?fr(L.basedir,t):t,u=L.outdir?pr(L.outdir,e):e;return L.extensionless?u:`${u}.${n}`}async function Ge(t,n,e,u){let r=Ar(n,u),l=await(u==="gz"?Xt:qt)(t,n);if(await ar(hr(r),{recursive:!0}),await ir(r,l),L.delete&&await cr(n),e){let a=Math.round(performance.now()-e),p=mr(t,l);console.info(`\u2713 compressed ${Me(r)} in ${a}ms ${p}`)}}async function br(t){let n=L.silent||!L.verbose?null:performance.now(),e=!1,u=!1;if(L.mtime&&Xt)try{let[r,l]=await Promise.all([ct(t),ct(`${t}.gz`)]);r&&l&&l.mtime>r.mtime&&(e=!0)}catch{}if(L.mtime&&qt)try{let[r,l]=await Promise.all([ct(t),ct(`${t}.br`)]);r&&l&&l.mtime>r.mtime&&(u=!0)}catch{}if(!(e&&u))try{let r=await sr(t);!e&&Xt&&await Ge(r,t,n,"gz"),!u&&qt&&await Ge(r,t,n,"br")}catch(r){console.info(`Error on ${t}: ${r.code} ${r.message}`)}}function Er(t,n,e){return e?.(t)?!1:n?n(t):!0}async function _r(){let t=L.silent?null:performance.now(),n=new Set(Be(L.include)),e=new Set([...Xe,...Be(L.exclude)]),u={include:n.size?Array.from(n):null,exclude:e.size?Array.from(e):null,followSymlinks:L.follow,insensitive:!L.sensitive},r={dot:!0,flags:L.sensitive?"i":void 0},l=n.size&&(0,kt.default)(Array.from(n),r),a=e.size&&(0,kt.default)(Array.from(e),r),p=[];for(let y of L._)if((await ct(y)).isDirectory())for await(let h of Dt(y,u))h.directory||p.push(h.path);else Er(y,l,a)&&p.push(L.follow?await ur(y):y);let b=`${p.length} file${p.length>1?"s":""}`;if(!p.length)throw new Error("No matching files found");L.silent||console.info(`precompress ${Kt} compressing ${b}...`);let _=L.concurrency>0?L.concurrency:Math.min(p.length,Ut);await St(p,br,{concurrency:_}),t&&console.info(Gt(`\u2713 ${b} done in ${Math.round(performance.now()-t)}ms`))}_r().then(Rt).catch(Rt); 24 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "precompress", 3 | "version": "12.0.7", 4 | "description": "CLI to compress files to gzip and brotli", 5 | "author": "silverwind ", 6 | "repository": "silverwind/precompress", 7 | "license": "BSD-2-Clause", 8 | "type": "module", 9 | "bin": "./dist/precompress.js", 10 | "engines": { 11 | "node": ">=18" 12 | }, 13 | "files": [ 14 | "dist/precompress.js" 15 | ], 16 | "devDependencies": { 17 | "esbuild": "0.25.0", 18 | "eslint": "8.57.0", 19 | "eslint-config-silverwind": "99.0.0", 20 | "execa": "9.5.2", 21 | "fast-glob": "3.3.3", 22 | "glowie": "1.3.2", 23 | "isbinaryfile": "5.0.4", 24 | "minimist": "1.2.8", 25 | "p-map": "7.0.3", 26 | "picomatch": "4.0.2", 27 | "rrdir": "13.2.1", 28 | "supports-color": "10.0.0", 29 | "typescript": "5.7.3", 30 | "typescript-config-silverwind": "8.0.0", 31 | "updates": "16.4.2", 32 | "versions": "12.1.3", 33 | "vitest": "3.0.5", 34 | "vitest-config-silverwind": "10.0.0" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /precompress.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import minimist from "minimist"; 3 | import pMap from "p-map"; 4 | import {rrdir} from "rrdir"; 5 | import {constants, gzip, brotliCompress} from "node:zlib"; 6 | import os from "node:os"; 7 | import {argv, exit, versions} from "node:process"; 8 | import {promisify} from "node:util"; 9 | import {stat, readFile, writeFile, realpath, mkdir, unlink} from "node:fs/promises"; 10 | import {extname, relative, join, dirname} from "node:path"; 11 | import {isBinaryFileSync} from "isbinaryfile"; 12 | import {readFileSync} from "node:fs"; 13 | import supportsColor from "supports-color"; 14 | import {green, magenta, red, yellow, disableColor} from "glowie"; 15 | import picomatch from "picomatch"; 16 | 17 | const alwaysExclude = ["**.gz", "**.br"]; 18 | const numCores = os.availableParallelism?.() ?? os.cpus().length ?? 4; 19 | 20 | // raise libuv threadpool over default 4 when more cores are available 21 | if (versions?.uv && numCores > 4) { 22 | process.env.UV_THREADPOOL_SIZE = String(numCores); 23 | } 24 | 25 | const args = minimist(argv.slice(2), { 26 | boolean: [ 27 | "d", "delete", 28 | "E", "extensionless", 29 | "f", "follow", 30 | "h", "help", 31 | "m", "mtime", 32 | "s", "silent", 33 | "S", "sensitive", 34 | "v", "version", 35 | "V", "verbose", 36 | ], 37 | string: [ 38 | "b", "basedir", 39 | "o", "outdir", 40 | "t", "types", 41 | "_" 42 | ], 43 | number: [ 44 | "c", "concurrency", 45 | ], 46 | alias: { 47 | b: "basedir", 48 | c: "concurrency", 49 | d: "delete", 50 | e: "exclude", 51 | E: "extensionless", 52 | h: "help", 53 | i: "include", 54 | o: "outdir", 55 | m: "mtime", 56 | s: "silent", 57 | S: "sensitive", 58 | t: "types", 59 | v: "version", 60 | V: "verbose", 61 | }, 62 | }); 63 | 64 | if (!supportsColor.stdout) disableColor(); 65 | 66 | function finish(err) { 67 | if (err) console.error(err.stack || err.message || err); 68 | exit(err ? 1 : 0); 69 | } 70 | 71 | let version = import.meta.VERSION; 72 | if (!version) { 73 | version = JSON.parse(readFileSync(new URL("package.json", import.meta.url))).version; 74 | } 75 | 76 | if (args.version) { 77 | console.info(import.meta.VERSION); 78 | finish(); 79 | } 80 | 81 | if (!args._.length || args.help) { 82 | console.info(`usage: precompress [options] 83 | 84 | Options: 85 | -t, --types Types of files to generate. Default: gz,br 86 | -i, --include Only include given globs. Default: unset 87 | -e, --exclude Exclude given globs. Default: ${alwaysExclude} 88 | -m, --mtime Skip creating existing files when source file is newer 89 | -f, --follow Follow symbolic links 90 | -d, --delete Delete source file after compression 91 | -o, --outdir Output directory, will preserve relative path structure 92 | -b, --basedir Base directory to derive output path, use with --outdir 93 | -E, --extensionless Do not output a extension, use with single --type and --outdir 94 | -s, --silent Do not print anything 95 | -S, --sensitive Treat include and exclude patterns case-sensitively 96 | -c, --concurrency Number of concurrent operations. Default: auto 97 | -V, --verbose Print individual file compression times 98 | -h, --help Show this text 99 | -v, --version Show the version 100 | 101 | Examples: 102 | $ precompress ./build`); 103 | finish(); 104 | } 105 | 106 | function getBrotliMode(data, path) { 107 | if (extname(path).toLowerCase() === ".woff2") { 108 | return constants.BROTLI_MODE_FONT; 109 | } else if (isBinaryFileSync(data)) { 110 | return constants.BROTLI_MODE_GENERIC; 111 | } else { 112 | return constants.BROTLI_MODE_TEXT; 113 | } 114 | } 115 | 116 | function reductionText(data, newData) { 117 | const change = (((newData.byteLength / data.byteLength) * 100)).toPrecision(3); 118 | 119 | if (change <= 80) { 120 | return `(${green(`${change}%`)} size)`; 121 | } else if (change < 100) { 122 | return `(${yellow(`${change}%`)} size)`; 123 | } else { 124 | return `(${red(`${change}%`)} size)`; 125 | } 126 | } 127 | 128 | const types = args.types ? args.types.split(",") : ["gz", "br"]; 129 | 130 | const gzipEncode = types.includes("gz") && ((data, _path) => promisify(gzip)(data, { 131 | level: constants.Z_BEST_COMPRESSION, 132 | })); 133 | const brotliEncode = types.includes("br") && ((data, path) => promisify(brotliCompress)(data, { 134 | params: { 135 | [constants.BROTLI_PARAM_MODE]: getBrotliMode(data, path), 136 | [constants.BROTLI_PARAM_QUALITY]: constants.BROTLI_MAX_QUALITY, 137 | } 138 | })); 139 | 140 | function argToArray(arg) { 141 | if (typeof arg === "boolean" || !arg) return []; 142 | return (Array.isArray(arg) ? arg : [arg]).flatMap(item => item.split(",")).filter(Boolean); 143 | } 144 | 145 | function getOutputPath(path, type) { 146 | const outPath = args.basedir ? relative(args.basedir, path) : path; 147 | const ret = args.outdir ? join(args.outdir, outPath) : outPath; 148 | return args.extensionless ? ret : `${ret}.${type}`; 149 | } 150 | 151 | async function compressFile(data, path, start, type) { 152 | const newPath = getOutputPath(path, type); 153 | const newData = await (type === "gz" ? gzipEncode : brotliEncode)(data, path); 154 | await mkdir(dirname(newPath), {recursive: true}); 155 | await writeFile(newPath, newData); 156 | if (args.delete) await unlink(path); 157 | 158 | if (start) { 159 | const ms = Math.round(performance.now() - start); 160 | const red = reductionText(data, newData); 161 | console.info(`✓ compressed ${magenta(newPath)} in ${ms}ms ${red}`); 162 | } 163 | } 164 | 165 | async function compress(path) { 166 | const start = (args.silent || !args.verbose) ? null : performance.now(); 167 | 168 | let skipGzip = false, skipBrotli = false; 169 | if (args.mtime && gzipEncode) { 170 | try { 171 | const [statsSource, statsTarget] = await Promise.all([stat(path), stat(`${path}.gz`)]); 172 | if (statsSource && statsTarget && statsTarget.mtime > statsSource.mtime) { 173 | skipGzip = true; 174 | } 175 | } catch {} 176 | } 177 | if (args.mtime && brotliEncode) { 178 | try { 179 | const [statsSource, statsTarget] = await Promise.all([stat(path), stat(`${path}.br`)]); 180 | if (statsSource && statsTarget && statsTarget.mtime > statsSource.mtime) { 181 | skipBrotli = true; 182 | } 183 | } catch {} 184 | } 185 | if (skipGzip && skipBrotli) return; 186 | 187 | try { 188 | const data = await readFile(path); 189 | 190 | if (!skipGzip && gzipEncode) { 191 | await compressFile(data, path, start, "gz"); 192 | } 193 | 194 | if (!skipBrotli && brotliEncode) { 195 | await compressFile(data, path, start, "br"); 196 | } 197 | } catch (err) { 198 | console.info(`Error on ${path}: ${err.code} ${err.message}`); 199 | } 200 | } 201 | 202 | function isIncluded(path, includeMatcher, excludeMatcher) { 203 | if (excludeMatcher?.(path)) return false; 204 | if (!includeMatcher) return true; 205 | return includeMatcher(path); 206 | } 207 | 208 | async function main() { 209 | const start = args.silent ? null : performance.now(); 210 | const includeGlobs = new Set(argToArray(args.include)); 211 | const excludeGlobs = new Set([...alwaysExclude, ...argToArray(args.exclude)]); 212 | 213 | const rrdirOpts = { 214 | include: includeGlobs.size ? Array.from(includeGlobs) : null, 215 | exclude: excludeGlobs.size ? Array.from(excludeGlobs) : null, 216 | followSymlinks: args.follow, 217 | insensitive: !args.sensitive, 218 | }; 219 | 220 | const picoOpts = {dot: true, flags: args.sensitive ? "i" : undefined}; 221 | const includeMatcher = includeGlobs.size && picomatch(Array.from(includeGlobs), picoOpts); 222 | const excludeMatcher = excludeGlobs.size && picomatch(Array.from(excludeGlobs), picoOpts); 223 | 224 | const files = []; 225 | for (const file of args._) { 226 | const stats = await stat(file); 227 | if (stats.isDirectory()) { 228 | for await (const entry of rrdir(file, rrdirOpts)) { 229 | if (!entry.directory) files.push(entry.path); 230 | } 231 | } else { 232 | if (isIncluded(file, includeMatcher, excludeMatcher)) { 233 | files.push(args.follow ? await realpath(file) : file); 234 | } 235 | } 236 | } 237 | 238 | const filesText = `${files.length} file${files.length > 1 ? "s" : ""}`; 239 | 240 | if (!files.length) throw new Error(`No matching files found`); 241 | if (!args.silent) console.info(`precompress ${version} compressing ${filesText}...`); 242 | 243 | const concurrency = args.concurrency > 0 ? args.concurrency : Math.min(files.length, numCores); 244 | await pMap(files, compress, {concurrency}); 245 | if (start) console.info(green( 246 | `✓ ${filesText} done in ${Math.round(performance.now() - start)}ms`, 247 | )); 248 | } 249 | 250 | main().then(finish).catch(finish); 251 | -------------------------------------------------------------------------------- /precompress.test.js: -------------------------------------------------------------------------------- 1 | import {execa} from "execa"; 2 | import {fileURLToPath} from "node:url"; 3 | import {writeFileSync, readFileSync, mkdirSync, statSync, mkdtempSync, rmSync} from "node:fs"; 4 | import {join} from "node:path"; 5 | import fastGlob from "fast-glob"; 6 | import {tmpdir} from "node:os"; 7 | 8 | const testDir = mkdtempSync(join(tmpdir(), "precompress-")); 9 | const script = fileURLToPath(new URL("dist/precompress.js", import.meta.url)); 10 | 11 | beforeEach(() => { 12 | rmSync(testDir, {recursive: true, force: true}); 13 | const srcDir = join(testDir, "src"); 14 | mkdirSync(srcDir, {recursive: true}); 15 | writeFileSync(join(testDir, "outer.html"), (new Array(1e4)).join("index")); 16 | writeFileSync(join(testDir, "already.gz"), (new Array(1e4)).join("index")); 17 | writeFileSync(join(testDir, "outer.png"), (new Array(1e4)).join("image")); 18 | writeFileSync(join(srcDir, "inner.js"), (new Array(1e4)).join("index")); 19 | writeFileSync(join(srcDir, "inner.css"), (new Array(1e4)).join("index")); 20 | }); 21 | 22 | afterAll(() => { 23 | rmSync(testDir, {recursive: true, force: true}); 24 | }); 25 | 26 | async function run(args) { 27 | const argsArr = [".", ...args.split(/\s+/).map(s => s.trim()).filter(Boolean)]; 28 | return execa(script, argsArr, {cwd: testDir}); 29 | } 30 | 31 | function makeTest(args) { 32 | return async () => { 33 | await run(args); 34 | const paths = fastGlob.sync(`**`, {cwd: testDir}).sort() 35 | .filter(p => !statSync(join(testDir, p)).isDirectory()); 36 | expect(paths).toMatchSnapshot(); 37 | }; 38 | } 39 | 40 | test("version", async () => { 41 | const {version} = JSON.parse(readFileSync(new URL("package.json", import.meta.url), "utf8")); 42 | const {stdout, exitCode} = await execa("node", [script, "-v"]); 43 | expect(stdout).toEqual(version); 44 | expect(exitCode).toEqual(0); 45 | }); 46 | 47 | test("simple", makeTest("")); 48 | test("delete", makeTest("-d")); 49 | test("include 1", makeTest("-i **.html,**.foo")); 50 | test("include 2", makeTest("-i **.HTML")); 51 | test("exclude 1", makeTest("-e **.png")); 52 | test("exclude 2", makeTest("-e **.png -e **.png,**.png")); 53 | test("exclude 3", makeTest("-e **.html")); 54 | test("exclude 4", makeTest("-e ''")); 55 | test("mtime", makeTest("-m")); 56 | test("outdir", makeTest(`-o ${testDir}/dist`)); 57 | test("outdir,basedir", makeTest(`-o ${testDir}/dist -b src`)); 58 | test("outdir,extensionless", makeTest(`-o ${testDir}/dist -t gz -E`)); 59 | 60 | test("no matching files 1", async () => { 61 | await expect(run("-e **.png,**.html -e **.js,**.css")).rejects.toThrow(); 62 | }); 63 | 64 | test("no matching files 2", async () => { 65 | await expect(run("-i HTML -S")).rejects.toThrow(); 66 | }); 67 | -------------------------------------------------------------------------------- /snapshots/precompress.test.js.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`delete 1`] = ` 4 | [ 5 | "already.gz", 6 | "outer.html.br", 7 | "outer.html.gz", 8 | "outer.png.br", 9 | "outer.png.gz", 10 | "src/inner.css.br", 11 | "src/inner.css.gz", 12 | "src/inner.js.br", 13 | "src/inner.js.gz", 14 | ] 15 | `; 16 | 17 | exports[`exclude 1 1`] = ` 18 | [ 19 | "already.gz", 20 | "outer.html", 21 | "outer.html.br", 22 | "outer.html.gz", 23 | "outer.png", 24 | "src/inner.css", 25 | "src/inner.css.br", 26 | "src/inner.css.gz", 27 | "src/inner.js", 28 | "src/inner.js.br", 29 | "src/inner.js.gz", 30 | ] 31 | `; 32 | 33 | exports[`exclude 2 1`] = ` 34 | [ 35 | "already.gz", 36 | "outer.html", 37 | "outer.html.br", 38 | "outer.html.gz", 39 | "outer.png", 40 | "src/inner.css", 41 | "src/inner.css.br", 42 | "src/inner.css.gz", 43 | "src/inner.js", 44 | "src/inner.js.br", 45 | "src/inner.js.gz", 46 | ] 47 | `; 48 | 49 | exports[`exclude 3 1`] = ` 50 | [ 51 | "already.gz", 52 | "outer.html", 53 | "outer.png", 54 | "outer.png.br", 55 | "outer.png.gz", 56 | "src/inner.css", 57 | "src/inner.css.br", 58 | "src/inner.css.gz", 59 | "src/inner.js", 60 | "src/inner.js.br", 61 | "src/inner.js.gz", 62 | ] 63 | `; 64 | 65 | exports[`exclude 4 1`] = ` 66 | [ 67 | "already.gz", 68 | "outer.html", 69 | "outer.html.br", 70 | "outer.html.gz", 71 | "outer.png", 72 | "outer.png.br", 73 | "outer.png.gz", 74 | "src/inner.css", 75 | "src/inner.css.br", 76 | "src/inner.css.gz", 77 | "src/inner.js", 78 | "src/inner.js.br", 79 | "src/inner.js.gz", 80 | ] 81 | `; 82 | 83 | exports[`include 1 1`] = ` 84 | [ 85 | "already.gz", 86 | "outer.html", 87 | "outer.html.br", 88 | "outer.html.gz", 89 | "outer.png", 90 | "src/inner.css", 91 | "src/inner.js", 92 | ] 93 | `; 94 | 95 | exports[`include 2 1`] = ` 96 | [ 97 | "already.gz", 98 | "outer.html", 99 | "outer.html.br", 100 | "outer.html.gz", 101 | "outer.png", 102 | "src/inner.css", 103 | "src/inner.js", 104 | ] 105 | `; 106 | 107 | exports[`mtime 1`] = ` 108 | [ 109 | "already.gz", 110 | "outer.html", 111 | "outer.html.br", 112 | "outer.html.gz", 113 | "outer.png", 114 | "outer.png.br", 115 | "outer.png.gz", 116 | "src/inner.css", 117 | "src/inner.css.br", 118 | "src/inner.css.gz", 119 | "src/inner.js", 120 | "src/inner.js.br", 121 | "src/inner.js.gz", 122 | ] 123 | `; 124 | 125 | exports[`outdir 1`] = ` 126 | [ 127 | "already.gz", 128 | "dist/outer.html.br", 129 | "dist/outer.html.gz", 130 | "dist/outer.png.br", 131 | "dist/outer.png.gz", 132 | "dist/src/inner.css.br", 133 | "dist/src/inner.css.gz", 134 | "dist/src/inner.js.br", 135 | "dist/src/inner.js.gz", 136 | "outer.html", 137 | "outer.png", 138 | "src/inner.css", 139 | "src/inner.js", 140 | ] 141 | `; 142 | 143 | exports[`outdir,basedir 1`] = ` 144 | [ 145 | "already.gz", 146 | "dist/inner.css.br", 147 | "dist/inner.css.gz", 148 | "dist/inner.js.br", 149 | "dist/inner.js.gz", 150 | "outer.html", 151 | "outer.html.br", 152 | "outer.html.gz", 153 | "outer.png", 154 | "outer.png.br", 155 | "outer.png.gz", 156 | "src/inner.css", 157 | "src/inner.js", 158 | ] 159 | `; 160 | 161 | exports[`outdir,extensionless 1`] = ` 162 | [ 163 | "already.gz", 164 | "dist/outer.html", 165 | "dist/outer.png", 166 | "dist/src/inner.css", 167 | "dist/src/inner.js", 168 | "outer.html", 169 | "outer.png", 170 | "src/inner.css", 171 | "src/inner.js", 172 | ] 173 | `; 174 | 175 | exports[`simple 1`] = ` 176 | [ 177 | "already.gz", 178 | "outer.html", 179 | "outer.html.br", 180 | "outer.html.gz", 181 | "outer.png", 182 | "outer.png.br", 183 | "outer.png.gz", 184 | "src/inner.css", 185 | "src/inner.css.br", 186 | "src/inner.css.gz", 187 | "src/inner.js", 188 | "src/inner.js.br", 189 | "src/inner.js.gz", 190 | ] 191 | `; 192 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "typescript-config-silverwind", 3 | "compilerOptions": { 4 | "strict": true, 5 | "types": [ 6 | "jest-extended", 7 | "vite/client", 8 | "vitest/globals", 9 | ], 10 | }, 11 | } 12 | -------------------------------------------------------------------------------- /updates.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | exclude: [ 3 | "eslint", // migrate to flat config first 4 | ], 5 | }; 6 | -------------------------------------------------------------------------------- /vitest.config.js: -------------------------------------------------------------------------------- 1 | import {defineConfig} from "vitest/config"; 2 | import {backend} from "vitest-config-silverwind"; 3 | 4 | export default defineConfig(backend({ 5 | url: import.meta.url, 6 | })); 7 | --------------------------------------------------------------------------------