@gjsify/workspace 0.4.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/lib/esm/_virtual/_rolldown/runtime.js +1 -0
- package/lib/esm/index.js +1 -0
- package/lib/tsconfig.build.tsbuildinfo +1 -0
- package/lib/types/index.d.ts +107 -0
- package/package.json +43 -0
- package/src/index.spec.ts +213 -0
- package/src/index.ts +391 -0
- package/src/test.mts +5 -0
- package/tsconfig.build.json +8 -0
- package/tsconfig.json +23 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var e=Object.defineProperty,__name=(t,n)=>e(t,`name`,{value:n,configurable:!0});export{__name};
|
package/lib/esm/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"./_virtual/_rolldown/runtime.js";import{existsSync as e,readFileSync as t,readdirSync as n,statSync as r}from"node:fs";import{dirname as i,join as a,relative as o,resolve as s,sep as c}from"node:path";function discoverWorkspaces(n,r={}){let i=a(n,`package.json`);if(!e(i))throw Error(`@gjsify/workspace: no package.json at ${n}`);let s=JSON.parse(t(i,`utf-8`)),l=r.patterns??extractWorkspacePatterns(s),u=[];r.includeRoot&&s.name&&u.push({location:n,relativeLocation:`.`,name:s.name,version:s.version??`0.0.0`,manifest:s,private:s.private===!0});for(let r of l)for(let i of expandPattern(n,r)){let r=a(i,`package.json`);if(!e(r))continue;let s;try{s=JSON.parse(t(r,`utf-8`))}catch{continue}s.name&&u.push({location:i,relativeLocation:o(n,i).split(c).join(`/`),name:s.name,version:s.version??`0.0.0`,manifest:s,private:s.private===!0})}return u.sort((e,t)=>e.relativeLocation.localeCompare(t.relativeLocation)),u}function resolveWorkspaceProtocol(e,t,n){if(!e.startsWith(`workspace:`))return;let r=e.slice(10),i=(n instanceof Map?n:indexByName(n)).get(t);if(!i)throw Error(`@gjsify/workspace: workspace dep "${t}" referenced as "${e}" but no workspace with that name was discovered`);let a=i.version;return r===`^`?`^${a}`:r===`~`?`~${a}`:r===`*`?a:r}function buildDependencyGraph(e,t={}){let n=t.includeDev??!1,r=t.includePeer??!1,i=t.includeOptional??!0,a=indexByName(e),o=new Map;for(let t of e){let e=new Set,s=t.manifest;for(let t of[s.dependencies,n?s.devDependencies:void 0,r?s.peerDependencies:void 0,i?s.optionalDependencies:void 0])if(t)for(let[n,r]of Object.entries(t))typeof r==`string`&&r.startsWith(`workspace:`)&&a.has(n)&&e.add(n);o.set(t.name,e)}return{edges:o,byName:a}}function topologicalSort(e){let t=new Map;for(let n of e.edges.keys())t.set(n,0);for(let n of e.edges.values())for(let e of n)t.has(e)&&t.set(e,(t.get(e)??0)+1);let n=new Map,r=new Map;for(let t of e.edges.keys())n.set(t,new Set),r.set(t,0);for(let[t,i]of e.edges)for(let e of i)n.has(e)&&(n.get(e).add(t),r.set(t,(r.get(t)??0)+1));let i=[];for(let[e,t]of r)t===0&&i.push(e);i.sort();let a=[];for(;i.length>0;){let t=i.shift(),o=e.byName.get(t);o&&a.push(o);let s=n.get(t);if(s){let e=[];for(let t of s){let n=(r.get(t)??1)-1;r.set(t,n),n===0&&e.push(t)}e.sort(),i.push(...e)}}if(a.length!==r.size){let e=[...r.entries()].filter(([,e])=>e>0).map(([e])=>e);throw Error(`@gjsify/workspace: dependency cycle detected involving ${e.join(`, `)}`)}return a}function filterWorkspaces(e,t){let n=t.include?.map(globToRegex),r=t.exclude?.map(globToRegex);return e.filter(e=>!(t.noPrivate&&e.private||n&&n.length>0&&!n.some(t=>t.test(e.name))||r&&r.length>0&&r.some(t=>t.test(e.name))))}function extractWorkspacePatterns(e){let t=e.workspaces;return t?Array.isArray(t)?t:t.packages??[]:[]}function expandPattern(t,i){let o=i.split(`/`).filter(Boolean),c=[s(t)];for(let t of o){let i=[];for(let o of c)if(t===`*`){let e=[];try{e=n(o)}catch{continue}for(let t of e){if(t.startsWith(`.`))continue;let e=a(o,t);try{r(e).isDirectory()&&i.push(e)}catch{}}}else if(t.includes(`*`)){let e=globToRegex(t),s=[];try{s=n(o)}catch{continue}for(let t of s){if(t.startsWith(`.`)||!e.test(t))continue;let n=a(o,t);try{r(n).isDirectory()&&i.push(n)}catch{}}}else{let n=a(o,t);if(e(n))try{r(n).isDirectory()&&i.push(n)}catch{}}c=i}return c}function globToRegex(e){let t=e.replace(/[.+?^${}()|[\]\\]/g,`\\$&`).replace(/\*/g,`[^/]*`);return RegExp(`^${t}$`)}function indexByName(e){let t=new Map;for(let n of e)t.set(n.name,n);return t}export{buildDependencyGraph,i as dirnamePath,discoverWorkspaces,filterWorkspaces,a as joinPath,resolveWorkspaceProtocol,topologicalSort};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"fileNames":["../../../../node_modules/typescript/lib/lib.es5.d.ts","../../../../node_modules/typescript/lib/lib.es2015.d.ts","../../../../node_modules/typescript/lib/lib.es2016.d.ts","../../../../node_modules/typescript/lib/lib.es2017.d.ts","../../../../node_modules/typescript/lib/lib.es2018.d.ts","../../../../node_modules/typescript/lib/lib.es2019.d.ts","../../../../node_modules/typescript/lib/lib.es2020.d.ts","../../../../node_modules/typescript/lib/lib.es2021.d.ts","../../../../node_modules/typescript/lib/lib.es2022.d.ts","../../../../node_modules/typescript/lib/lib.es2023.d.ts","../../../../node_modules/typescript/lib/lib.es2024.d.ts","../../../../node_modules/typescript/lib/lib.es2025.d.ts","../../../../node_modules/typescript/lib/lib.esnext.d.ts","../../../../node_modules/typescript/lib/lib.dom.d.ts","../../../../node_modules/typescript/lib/lib.dom.iterable.d.ts","../../../../node_modules/typescript/lib/lib.dom.asynciterable.d.ts","../../../../node_modules/typescript/lib/lib.webworker.importscripts.d.ts","../../../../node_modules/typescript/lib/lib.scripthost.d.ts","../../../../node_modules/typescript/lib/lib.es2015.core.d.ts","../../../../node_modules/typescript/lib/lib.es2015.collection.d.ts","../../../../node_modules/typescript/lib/lib.es2015.generator.d.ts","../../../../node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../../../node_modules/typescript/lib/lib.es2015.promise.d.ts","../../../../node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../../../node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../../../node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../../../node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../../../node_modules/typescript/lib/lib.es2016.array.include.d.ts","../../../../node_modules/typescript/lib/lib.es2016.intl.d.ts","../../../../node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","../../../../node_modules/typescript/lib/lib.es2017.date.d.ts","../../../../node_modules/typescript/lib/lib.es2017.object.d.ts","../../../../node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../../../../node_modules/typescript/lib/lib.es2017.string.d.ts","../../../../node_modules/typescript/lib/lib.es2017.intl.d.ts","../../../../node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../../../../node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../../../../node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../../../../node_modules/typescript/lib/lib.es2018.intl.d.ts","../../../../node_modules/typescript/lib/lib.es2018.promise.d.ts","../../../../node_modules/typescript/lib/lib.es2018.regexp.d.ts","../../../../node_modules/typescript/lib/lib.es2019.array.d.ts","../../../../node_modules/typescript/lib/lib.es2019.object.d.ts","../../../../node_modules/typescript/lib/lib.es2019.string.d.ts","../../../../node_modules/typescript/lib/lib.es2019.symbol.d.ts","../../../../node_modules/typescript/lib/lib.es2019.intl.d.ts","../../../../node_modules/typescript/lib/lib.es2020.bigint.d.ts","../../../../node_modules/typescript/lib/lib.es2020.date.d.ts","../../../../node_modules/typescript/lib/lib.es2020.promise.d.ts","../../../../node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../../../../node_modules/typescript/lib/lib.es2020.string.d.ts","../../../../node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../../../../node_modules/typescript/lib/lib.es2020.intl.d.ts","../../../../node_modules/typescript/lib/lib.es2020.number.d.ts","../../../../node_modules/typescript/lib/lib.es2021.promise.d.ts","../../../../node_modules/typescript/lib/lib.es2021.string.d.ts","../../../../node_modules/typescript/lib/lib.es2021.weakref.d.ts","../../../../node_modules/typescript/lib/lib.es2021.intl.d.ts","../../../../node_modules/typescript/lib/lib.es2022.array.d.ts","../../../../node_modules/typescript/lib/lib.es2022.error.d.ts","../../../../node_modules/typescript/lib/lib.es2022.intl.d.ts","../../../../node_modules/typescript/lib/lib.es2022.object.d.ts","../../../../node_modules/typescript/lib/lib.es2022.string.d.ts","../../../../node_modules/typescript/lib/lib.es2022.regexp.d.ts","../../../../node_modules/typescript/lib/lib.es2023.array.d.ts","../../../../node_modules/typescript/lib/lib.es2023.collection.d.ts","../../../../node_modules/typescript/lib/lib.es2023.intl.d.ts","../../../../node_modules/typescript/lib/lib.es2024.arraybuffer.d.ts","../../../../node_modules/typescript/lib/lib.es2024.collection.d.ts","../../../../node_modules/typescript/lib/lib.es2024.object.d.ts","../../../../node_modules/typescript/lib/lib.es2024.promise.d.ts","../../../../node_modules/typescript/lib/lib.es2024.regexp.d.ts","../../../../node_modules/typescript/lib/lib.es2024.sharedmemory.d.ts","../../../../node_modules/typescript/lib/lib.es2024.string.d.ts","../../../../node_modules/typescript/lib/lib.es2025.collection.d.ts","../../../../node_modules/typescript/lib/lib.es2025.float16.d.ts","../../../../node_modules/typescript/lib/lib.es2025.intl.d.ts","../../../../node_modules/typescript/lib/lib.es2025.iterator.d.ts","../../../../node_modules/typescript/lib/lib.es2025.promise.d.ts","../../../../node_modules/typescript/lib/lib.es2025.regexp.d.ts","../../../../node_modules/typescript/lib/lib.esnext.array.d.ts","../../../../node_modules/typescript/lib/lib.esnext.collection.d.ts","../../../../node_modules/typescript/lib/lib.esnext.date.d.ts","../../../../node_modules/typescript/lib/lib.esnext.decorators.d.ts","../../../../node_modules/typescript/lib/lib.esnext.disposable.d.ts","../../../../node_modules/typescript/lib/lib.esnext.error.d.ts","../../../../node_modules/typescript/lib/lib.esnext.intl.d.ts","../../../../node_modules/typescript/lib/lib.esnext.sharedmemory.d.ts","../../../../node_modules/typescript/lib/lib.esnext.temporal.d.ts","../../../../node_modules/typescript/lib/lib.esnext.typedarrays.d.ts","../../../../node_modules/typescript/lib/lib.decorators.d.ts","../../../../node_modules/typescript/lib/lib.decorators.legacy.d.ts","../../../../node_modules/typescript/lib/lib.esnext.full.d.ts","../src/index.ts","../../../../node_modules/@types/node/compatibility/iterators.d.ts","../../../../node_modules/@types/node/globals.typedarray.d.ts","../../../../node_modules/@types/node/buffer.buffer.d.ts","../../../../node_modules/@types/node/globals.d.ts","../../../../node_modules/@types/node/web-globals/abortcontroller.d.ts","../../../../node_modules/@types/node/web-globals/blob.d.ts","../../../../node_modules/@types/node/web-globals/console.d.ts","../../../../node_modules/@types/node/web-globals/crypto.d.ts","../../../../node_modules/@types/node/web-globals/domexception.d.ts","../../../../node_modules/@types/node/web-globals/encoding.d.ts","../../../../node_modules/@types/node/web-globals/events.d.ts","../../../../node_modules/undici-types/utility.d.ts","../../../../node_modules/undici-types/header.d.ts","../../../../node_modules/undici-types/readable.d.ts","../../../../node_modules/undici-types/fetch.d.ts","../../../../node_modules/undici-types/formdata.d.ts","../../../../node_modules/undici-types/connector.d.ts","../../../../node_modules/undici-types/client-stats.d.ts","../../../../node_modules/undici-types/client.d.ts","../../../../node_modules/undici-types/errors.d.ts","../../../../node_modules/undici-types/dispatcher.d.ts","../../../../node_modules/undici-types/global-dispatcher.d.ts","../../../../node_modules/undici-types/global-origin.d.ts","../../../../node_modules/undici-types/pool-stats.d.ts","../../../../node_modules/undici-types/pool.d.ts","../../../../node_modules/undici-types/handlers.d.ts","../../../../node_modules/undici-types/balanced-pool.d.ts","../../../../node_modules/undici-types/round-robin-pool.d.ts","../../../../node_modules/undici-types/h2c-client.d.ts","../../../../node_modules/undici-types/agent.d.ts","../../../../node_modules/undici-types/mock-interceptor.d.ts","../../../../node_modules/undici-types/mock-call-history.d.ts","../../../../node_modules/undici-types/mock-agent.d.ts","../../../../node_modules/undici-types/mock-client.d.ts","../../../../node_modules/undici-types/mock-pool.d.ts","../../../../node_modules/undici-types/snapshot-agent.d.ts","../../../../node_modules/undici-types/mock-errors.d.ts","../../../../node_modules/undici-types/proxy-agent.d.ts","../../../../node_modules/undici-types/env-http-proxy-agent.d.ts","../../../../node_modules/undici-types/retry-handler.d.ts","../../../../node_modules/undici-types/retry-agent.d.ts","../../../../node_modules/undici-types/api.d.ts","../../../../node_modules/undici-types/cache-interceptor.d.ts","../../../../node_modules/undici-types/interceptors.d.ts","../../../../node_modules/undici-types/util.d.ts","../../../../node_modules/undici-types/cookies.d.ts","../../../../node_modules/undici-types/patch.d.ts","../../../../node_modules/undici-types/websocket.d.ts","../../../../node_modules/undici-types/eventsource.d.ts","../../../../node_modules/undici-types/diagnostics-channel.d.ts","../../../../node_modules/undici-types/content-type.d.ts","../../../../node_modules/undici-types/cache.d.ts","../../../../node_modules/undici-types/index.d.ts","../../../../node_modules/@types/node/web-globals/fetch.d.ts","../../../../node_modules/@types/node/web-globals/importmeta.d.ts","../../../../node_modules/@types/node/web-globals/messaging.d.ts","../../../../node_modules/@types/node/web-globals/navigator.d.ts","../../../../node_modules/@types/node/web-globals/performance.d.ts","../../../../node_modules/@types/node/web-globals/storage.d.ts","../../../../node_modules/@types/node/web-globals/streams.d.ts","../../../../node_modules/@types/node/web-globals/timers.d.ts","../../../../node_modules/@types/node/web-globals/url.d.ts","../../../../node_modules/@types/node/assert.d.ts","../../../../node_modules/@types/node/assert/strict.d.ts","../../../../node_modules/@types/node/async_hooks.d.ts","../../../../node_modules/@types/node/buffer.d.ts","../../../../node_modules/@types/node/child_process.d.ts","../../../../node_modules/@types/node/cluster.d.ts","../../../../node_modules/@types/node/console.d.ts","../../../../node_modules/@types/node/constants.d.ts","../../../../node_modules/@types/node/crypto.d.ts","../../../../node_modules/@types/node/dgram.d.ts","../../../../node_modules/@types/node/diagnostics_channel.d.ts","../../../../node_modules/@types/node/dns.d.ts","../../../../node_modules/@types/node/dns/promises.d.ts","../../../../node_modules/@types/node/domain.d.ts","../../../../node_modules/@types/node/events.d.ts","../../../../node_modules/@types/node/fs.d.ts","../../../../node_modules/@types/node/fs/promises.d.ts","../../../../node_modules/@types/node/http.d.ts","../../../../node_modules/@types/node/http2.d.ts","../../../../node_modules/@types/node/https.d.ts","../../../../node_modules/@types/node/inspector.d.ts","../../../../node_modules/@types/node/inspector.generated.d.ts","../../../../node_modules/@types/node/inspector/promises.d.ts","../../../../node_modules/@types/node/module.d.ts","../../../../node_modules/@types/node/net.d.ts","../../../../node_modules/buffer/index.d.ts","../../../../node_modules/@types/node/os.d.ts","../../../../node_modules/@types/node/path.d.ts","../../../../node_modules/@types/node/path/posix.d.ts","../../../../node_modules/@types/node/path/win32.d.ts","../../../../node_modules/@types/node/perf_hooks.d.ts","../../../../node_modules/@types/node/process.d.ts","../../../../node_modules/@types/node/punycode.d.ts","../../../../node_modules/@types/node/querystring.d.ts","../../../../node_modules/@types/node/quic.d.ts","../../../../node_modules/@types/node/readline.d.ts","../../../../node_modules/@types/node/readline/promises.d.ts","../../../../node_modules/@types/node/repl.d.ts","../../../../node_modules/@types/node/sea.d.ts","../../../../node_modules/@types/node/sqlite.d.ts","../../../../node_modules/@types/node/stream.d.ts","../../../../node_modules/@types/node/stream/consumers.d.ts","../../../../node_modules/@types/node/stream/promises.d.ts","../../../../node_modules/@types/node/stream/web.d.ts","../../../../node_modules/@types/node/string_decoder.d.ts","../../../../node_modules/@types/node/test.d.ts","../../../../node_modules/@types/node/test/reporters.d.ts","../../../../node_modules/@types/node/timers.d.ts","../../../../node_modules/@types/node/timers/promises.d.ts","../../../../node_modules/@types/node/tls.d.ts","../../../../node_modules/@types/node/trace_events.d.ts","../../../../node_modules/@types/node/tty.d.ts","../../../../node_modules/@types/node/url.d.ts","../../../../node_modules/@types/node/util.d.ts","../../../../node_modules/@types/node/util/types.d.ts","../../../../node_modules/@types/node/v8.d.ts","../../../../node_modules/@types/node/vm.d.ts","../../../../node_modules/@types/node/wasi.d.ts","../../../../node_modules/@types/node/worker_threads.d.ts","../../../../node_modules/@types/node/zlib.d.ts","../../../../node_modules/@types/node/index.d.ts"],"fileIdsList":[[97,157,158,160,168,172,175,177,178,179,192],[97,159,160,168,172,175,177,178,179,192],[160,168,172,175,177,178,179,192],[97,160,168,172,175,177,178,179,192,200],[97,160,161,166,168,171,172,175,177,178,179,181,192,197,209],[97,160,161,162,168,171,172,175,177,178,179,192],[97,160,168,172,175,177,178,179,192],[97,160,163,168,172,175,177,178,179,192,210],[97,160,164,165,168,172,175,177,178,179,183,192],[97,160,165,168,172,175,177,178,179,192,197,206],[97,160,166,168,171,172,175,177,178,179,181,192],[97,159,160,167,168,172,175,177,178,179,192],[97,160,168,169,172,175,177,178,179,192],[97,160,168,170,171,172,175,177,178,179,192],[97,159,160,168,171,172,175,177,178,179,192],[97,160,168,171,172,173,175,177,178,179,192,197,209],[97,160,168,171,172,173,175,177,178,179,192,197,200],[97,147,160,168,171,172,174,175,177,178,179,181,192,197,209],[97,160,168,171,172,174,175,177,178,179,181,192,197,206,209],[97,160,168,172,174,175,176,177,178,179,192,197,206,209],[95,96,97,98,99,100,101,102,103,104,105,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216],[97,160,168,171,172,175,177,178,179,192],[97,160,168,172,175,177,179,192],[97,160,168,172,175,177,178,179,180,192,209],[97,160,168,171,172,175,177,178,179,181,192,197],[97,160,168,172,175,177,178,179,183,192],[97,160,168,172,175,177,178,179,184,192],[97,160,168,171,172,175,177,178,179,187,192],[97,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216],[97,160,168,172,175,177,178,179,189,192],[97,160,168,172,175,177,178,179,190,192],[97,160,165,168,172,175,177,178,179,181,192,200],[97,160,168,171,172,175,177,178,179,192,193],[97,160,168,172,175,177,178,179,192,194,210,213],[97,160,168,171,172,175,177,178,179,192,197,199,200],[97,160,168,172,175,177,178,179,192,198,200],[97,160,168,172,175,177,178,179,192,200,210],[97,160,168,172,175,177,178,179,192,201],[97,157,160,168,172,175,177,178,179,192,197,203,209],[97,160,168,172,175,177,178,179,192,197,202],[97,160,168,171,172,175,177,178,179,192,204,205],[97,160,168,172,175,177,178,179,192,204,205],[97,160,165,168,172,175,177,178,179,181,192,197,206],[97,160,168,172,175,177,178,179,192,207],[97,160,168,172,175,177,178,179,181,192,208],[97,160,168,172,174,175,177,178,179,190,192,209],[97,160,168,172,175,177,178,179,192,210,211],[97,160,165,168,172,175,177,178,179,192,211],[97,160,168,172,175,177,178,179,192,197,212],[97,160,168,172,175,177,178,179,180,192,213],[97,160,168,172,175,177,178,179,192,214],[97,160,163,168,172,175,177,178,179,192],[97,160,165,168,172,175,177,178,179,192],[97,160,168,172,175,177,178,179,192,210],[97,147,160,168,172,175,177,178,179,192],[97,160,168,172,175,177,178,179,192,209],[97,160,168,172,175,177,178,179,192,215],[97,160,168,172,175,177,178,179,187,192],[97,160,168,172,175,177,178,179,192,205],[97,147,160,168,171,172,173,175,177,178,179,187,192,197,200,209,212,213,215],[97,160,168,172,175,177,178,179,192,197,216],[97,112,115,118,119,160,168,172,175,177,178,179,192,209],[97,115,160,168,172,175,177,178,179,192,197,209],[97,115,119,160,168,172,175,177,178,179,192,209],[97,160,168,172,175,177,178,179,192,197],[97,109,160,168,172,175,177,178,179,192],[97,113,160,168,172,175,177,178,179,192],[97,111,112,115,160,168,172,175,177,178,179,192,209],[97,160,168,172,175,177,178,179,181,192,206],[97,160,168,172,175,177,178,179,192,217],[97,109,160,168,172,175,177,178,179,192,217],[97,111,115,160,168,172,175,177,178,179,181,192,209],[97,106,107,108,110,114,160,168,171,172,175,177,178,179,192,197,209],[97,115,124,132,160,168,172,175,177,178,179,192],[97,107,113,160,168,172,175,177,178,179,192],[97,115,141,142,160,168,172,175,177,178,179,192],[97,107,110,115,160,168,172,175,177,178,179,192,200,209,217],[97,115,160,168,172,175,177,178,179,192],[97,111,115,160,168,172,175,177,178,179,192,209],[97,106,160,168,172,175,177,178,179,192],[97,109,110,111,113,114,115,116,117,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,142,143,144,145,146,160,168,172,175,177,178,179,192],[97,115,134,137,160,168,172,175,177,178,179,192],[97,115,124,125,126,160,168,172,175,177,178,179,192],[97,113,115,125,127,160,168,172,175,177,178,179,192],[97,114,160,168,172,175,177,178,179,192],[97,107,109,115,160,168,172,175,177,178,179,192],[97,115,119,125,127,160,168,172,175,177,178,179,192],[97,119,160,168,172,175,177,178,179,192],[97,113,115,118,160,168,172,175,177,178,179,192,209],[97,107,111,115,124,160,168,172,175,177,178,179,192],[97,115,134,160,168,172,175,177,178,179,192],[97,127,160,168,172,175,177,178,179,192],[97,109,115,141,160,168,172,175,177,178,179,192,200,215,217]],"fileInfos":[{"version":"bcd24271a113971ba9eb71ff8cb01bc6b0f872a85c23fdbe5d93065b375933cd","affectsGlobalScope":true,"impliedFormat":1},{"version":"3f88bedbeb09c6f5a6645cb24c7c55f1aa22d19ae96c8e6959cbd8b85a707bc6","impliedFormat":1},{"version":"7fe93b39b810eadd916be8db880dd7f0f7012a5cc6ffb62de8f62a2117fa6f1f","impliedFormat":1},{"version":"bb0074cc08b84a2374af33d8bf044b80851ccc9e719a5e202eacf40db2c31600","impliedFormat":1},{"version":"1a7daebe4f45fb03d9ec53d60008fbf9ac45a697fdc89e4ce218bc94b94f94d6","impliedFormat":1},{"version":"f94b133a3cb14a288803be545ac2683e0d0ff6661bcd37e31aaaec54fc382aed","impliedFormat":1},{"version":"f59d0650799f8782fd74cf73c19223730c6d1b9198671b1c5b3a38e1188b5953","impliedFormat":1},{"version":"8a15b4607d9a499e2dbeed9ec0d3c0d7372c850b2d5f1fb259e8f6d41d468a84","impliedFormat":1},{"version":"26e0fe14baee4e127f4365d1ae0b276f400562e45e19e35fd2d4c296684715e6","impliedFormat":1},{"version":"1e9332c23e9a907175e0ffc6a49e236f97b48838cc8aec9ce7e4cec21e544b65","impliedFormat":1},{"version":"3753fbc1113dc511214802a2342280a8b284ab9094f6420e7aa171e868679f91","impliedFormat":1},{"version":"999ca32883495a866aa5737fe1babc764a469e4cde6ee6b136a4b9ae68853e4b","impliedFormat":1},{"version":"17f13ecb98cbc39243f2eee1f16d45cd8ec4706b03ee314f1915f1a8b42f6984","impliedFormat":1},{"version":"d6b1eba8496bdd0eed6fc8a685768fe01b2da4a0388b5fe7df558290bffcf32f","affectsGlobalScope":true,"impliedFormat":1},{"version":"7f57fc4404ff020bc45b9c620aff2b40f700b95fe31164024c453a5e3c163c54","impliedFormat":1},{"version":"7f57fc4404ff020bc45b9c620aff2b40f700b95fe31164024c453a5e3c163c54","impliedFormat":1},{"version":"2a2de5b9459b3fc44decd9ce6100b72f1b002ef523126c1d3d8b2a4a63d74d78","affectsGlobalScope":true,"impliedFormat":1},{"version":"f13f4b465c99041e912db5c44129a94588e1aafee35a50eab51044833f50b4ee","affectsGlobalScope":true,"impliedFormat":1},{"version":"eadcffda2aa84802c73938e589b9e58248d74c59cb7fcbca6474e3435ac15504","affectsGlobalScope":true,"impliedFormat":1},{"version":"105ba8ff7ba746404fe1a2e189d1d3d2e0eb29a08c18dded791af02f29fb4711","affectsGlobalScope":true,"impliedFormat":1},{"version":"00343ca5b2e3d48fa5df1db6e32ea2a59afab09590274a6cccb1dbae82e60c7c","affectsGlobalScope":true,"impliedFormat":1},{"version":"ebd9f816d4002697cb2864bea1f0b70a103124e18a8cd9645eeccc09bdf80ab4","affectsGlobalScope":true,"impliedFormat":1},{"version":"2c1afac30a01772cd2a9a298a7ce7706b5892e447bb46bdbeef720f7b5da77ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"7b0225f483e4fa685625ebe43dd584bb7973bbd84e66a6ba7bbe175ee1048b4f","affectsGlobalScope":true,"impliedFormat":1},{"version":"c0a4b8ac6ce74679c1da2b3795296f5896e31c38e888469a8e0f99dc3305de60","affectsGlobalScope":true,"impliedFormat":1},{"version":"3084a7b5f569088e0146533a00830e206565de65cae2239509168b11434cd84f","affectsGlobalScope":true,"impliedFormat":1},{"version":"c5079c53f0f141a0698faa903e76cb41cd664e3efb01cc17a5c46ec2eb0bef42","affectsGlobalScope":true,"impliedFormat":1},{"version":"32cafbc484dea6b0ab62cf8473182bbcb23020d70845b406f80b7526f38ae862","affectsGlobalScope":true,"impliedFormat":1},{"version":"fca4cdcb6d6c5ef18a869003d02c9f0fd95df8cfaf6eb431cd3376bc034cad36","affectsGlobalScope":true,"impliedFormat":1},{"version":"b93ec88115de9a9dc1b602291b85baf825c85666bf25985cc5f698073892b467","affectsGlobalScope":true,"impliedFormat":1},{"version":"f5c06dcc3fe849fcb297c247865a161f995cc29de7aa823afdd75aaaddc1419b","affectsGlobalScope":true,"impliedFormat":1},{"version":"b77e16112127a4b169ef0b8c3a4d730edf459c5f25fe52d5e436a6919206c4d7","affectsGlobalScope":true,"impliedFormat":1},{"version":"fbffd9337146eff822c7c00acbb78b01ea7ea23987f6c961eba689349e744f8c","affectsGlobalScope":true,"impliedFormat":1},{"version":"a995c0e49b721312f74fdfb89e4ba29bd9824c770bbb4021d74d2bf560e4c6bd","affectsGlobalScope":true,"impliedFormat":1},{"version":"c7b3542146734342e440a84b213384bfa188835537ddbda50d30766f0593aff9","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce6180fa19b1cccd07ee7f7dbb9a367ac19c0ed160573e4686425060b6df7f57","affectsGlobalScope":true,"impliedFormat":1},{"version":"3f02e2476bccb9dbe21280d6090f0df17d2f66b74711489415a8aa4df73c9675","affectsGlobalScope":true,"impliedFormat":1},{"version":"45e3ab34c1c013c8ab2dc1ba4c80c780744b13b5676800ae2e3be27ae862c40c","affectsGlobalScope":true,"impliedFormat":1},{"version":"805c86f6cca8d7702a62a844856dbaa2a3fd2abef0536e65d48732441dde5b5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"e42e397f1a5a77994f0185fd1466520691456c772d06bf843e5084ceb879a0ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"f4c2b41f90c95b1c532ecc874bd3c111865793b23aebcc1c3cbbabcd5d76ffb0","affectsGlobalScope":true,"impliedFormat":1},{"version":"ab26191cfad5b66afa11b8bf935ef1cd88fabfcb28d30b2dfa6fad877d050332","affectsGlobalScope":true,"impliedFormat":1},{"version":"2088bc26531e38fb05eedac2951480db5309f6be3fa4a08d2221abb0f5b4200d","affectsGlobalScope":true,"impliedFormat":1},{"version":"cb9d366c425fea79716a8fb3af0d78e6b22ebbab3bd64d25063b42dc9f531c1e","affectsGlobalScope":true,"impliedFormat":1},{"version":"500934a8089c26d57ebdb688fc9757389bb6207a3c8f0674d68efa900d2abb34","affectsGlobalScope":true,"impliedFormat":1},{"version":"689da16f46e647cef0d64b0def88910e818a5877ca5379ede156ca3afb780ac3","affectsGlobalScope":true,"impliedFormat":1},{"version":"bc21cc8b6fee4f4c2440d08035b7ea3c06b3511314c8bab6bef7a92de58a2593","affectsGlobalScope":true,"impliedFormat":1},{"version":"7ca53d13d2957003abb47922a71866ba7cb2068f8d154877c596d63c359fed25","affectsGlobalScope":true,"impliedFormat":1},{"version":"54725f8c4df3d900cb4dac84b64689ce29548da0b4e9b7c2de61d41c79293611","affectsGlobalScope":true,"impliedFormat":1},{"version":"e5594bc3076ac29e6c1ebda77939bc4c8833de72f654b6e376862c0473199323","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f3eb332c2d73e729f3364fcc0c2b375e72a121e8157d25a82d67a138c83a95c","affectsGlobalScope":true,"impliedFormat":1},{"version":"6f4427f9642ce8d500970e4e69d1397f64072ab73b97e476b4002a646ac743b1","affectsGlobalScope":true,"impliedFormat":1},{"version":"48915f327cd1dea4d7bd358d9dc7732f58f9e1626a29cc0c05c8c692419d9bb7","affectsGlobalScope":true,"impliedFormat":1},{"version":"b7bf9377723203b5a6a4b920164df22d56a43f593269ba6ae1fdc97774b68855","affectsGlobalScope":true,"impliedFormat":1},{"version":"db9709688f82c9e5f65a119c64d835f906efe5f559d08b11642d56eb85b79357","affectsGlobalScope":true,"impliedFormat":1},{"version":"4b25b8c874acd1a4cf8444c3617e037d444d19080ac9f634b405583fd10ce1f7","affectsGlobalScope":true,"impliedFormat":1},{"version":"37be57d7c90cf1f8112ee2636a068d8fd181289f82b744160ec56a7dc158a9f5","affectsGlobalScope":true,"impliedFormat":1},{"version":"a917a49ac94cd26b754ab84e113369a75d1a47a710661d7cd25e961cc797065f","affectsGlobalScope":true,"impliedFormat":1},{"version":"6d3261badeb7843d157ef3e6f5d1427d0eeb0af0cf9df84a62cfd29fd47ac86e","affectsGlobalScope":true,"impliedFormat":1},{"version":"195daca651dde22f2167ac0d0a05e215308119a3100f5e6268e8317d05a92526","affectsGlobalScope":true,"impliedFormat":1},{"version":"8b11e4285cd2bb164a4dc09248bdec69e9842517db4ca47c1ba913011e44ff2f","affectsGlobalScope":true,"impliedFormat":1},{"version":"0508571a52475e245b02bc50fa1394065a0a3d05277fbf5120c3784b85651799","affectsGlobalScope":true,"impliedFormat":1},{"version":"8f9af488f510c3015af3cc8c267a9e9d96c4dd38a1fdff0e11dc5a544711415b","affectsGlobalScope":true,"impliedFormat":1},{"version":"fc611fea8d30ea72c6bbfb599c9b4d393ce22e2f5bfef2172534781e7d138104","affectsGlobalScope":true,"impliedFormat":1},{"version":"0bd714129fca875f7d4c477a1a392200b0bcd13fb2e80928cd334b63830ea047","affectsGlobalScope":true,"impliedFormat":1},{"version":"e2c9037ae6cd2c52d80ceef0b3c5ffdb488627d71529cf4f63776daf11161c9a","affectsGlobalScope":true,"impliedFormat":1},{"version":"135d5cf4d345f59f1a9caadfafcd858d3d9cc68290db616cc85797224448cccc","affectsGlobalScope":true,"impliedFormat":1},{"version":"bc238c3f81c2984751932b6aab223cd5b830e0ac6cad76389e5e9d2ffc03287d","affectsGlobalScope":true,"impliedFormat":1},{"version":"4a07f9b76d361f572620927e5735b77d6d2101c23cdd94383eb5b706e7b36357","affectsGlobalScope":true,"impliedFormat":1},{"version":"7c4e8dc6ab834cc6baa0227e030606d29e3e8449a9f67cdf5605ea5493c4db29","affectsGlobalScope":true,"impliedFormat":1},{"version":"de7ba0fd02e06cd9a5bd4ab441ed0e122735786e67dde1e849cced1cd8b46b78","affectsGlobalScope":true,"impliedFormat":1},{"version":"6148e4e88d720a06855071c3db02069434142a8332cf9c182cda551adedf3156","affectsGlobalScope":true,"impliedFormat":1},{"version":"d63dba625b108316a40c95a4425f8d4294e0deeccfd6c7e59d819efa19e23409","affectsGlobalScope":true,"impliedFormat":1},{"version":"0568d6befee03dd435bed4fc25c4e46865b24bdcb8c563fdc21f580a2c301904","affectsGlobalScope":true,"impliedFormat":1},{"version":"30d62269b05b584741f19a5369852d5d34895aa2ac4fd948956f886d15f9cc0d","affectsGlobalScope":true,"impliedFormat":1},{"version":"f128dae7c44d8f35ee42e0a437000a57c9f06cc04f8b4fb42eebf44954d53dc8","affectsGlobalScope":true,"impliedFormat":1},{"version":"ffbe6d7b295306b2ba88030f65b74c107d8d99bdcf596ea99c62a02f606108b0","affectsGlobalScope":true,"impliedFormat":1},{"version":"996fb27b15277369c68a4ba46ed138b4e9e839a02fb4ec756f7997629242fd9f","affectsGlobalScope":true,"impliedFormat":1},{"version":"79b712591b270d4778c89706ca2cfc56ddb8c3f895840e477388f1710dc5eda9","affectsGlobalScope":true,"impliedFormat":1},{"version":"20884846cef428b992b9bd032e70a4ef88e349263f63aeddf04dda837a7dba26","affectsGlobalScope":true,"impliedFormat":1},{"version":"5fcab789c73a97cd43828ee3cc94a61264cf24d4c44472ce64ced0e0f148bdb2","affectsGlobalScope":true,"impliedFormat":1},{"version":"db59a81f070c1880ad645b2c0275022baa6a0c4f0acdc58d29d349c6efcf0903","affectsGlobalScope":true,"impliedFormat":1},{"version":"673294292640f5722b700e7d814e17aaf7d93f83a48a2c9b38f33cbc940ad8b0","affectsGlobalScope":true,"impliedFormat":1},{"version":"d786b48f934cbca483b3c6d0a798cb43bbb4ada283e76fb22c28e53ae05b9e69","affectsGlobalScope":true,"impliedFormat":1},{"version":"1ecb8e347cb6b2a8927c09b86263663289418df375f5e68e11a0ae683776978f","affectsGlobalScope":true,"impliedFormat":1},{"version":"142efd4ce210576f777dc34df121777be89eda476942d6d6663b03dcb53be3ff","affectsGlobalScope":true,"impliedFormat":1},{"version":"379bc41580c2d774f82e828c70308f24a005b490c25ba34d679d84bcf05c3d9d","affectsGlobalScope":true,"impliedFormat":1},{"version":"ed484fb2aa8a1a23d0277056ec3336e0a0b52f9b8d6a961f338a642faf43235d","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ffedae1d1c2d53fdbca1c96d3c7dda544281f7d262f99b6880634f8fd8d9820","affectsGlobalScope":true,"impliedFormat":1},{"version":"83a730b125d477dd264df8ba479afab27a3dae7152b005c214ab94dc7ee44fd3","affectsGlobalScope":true,"impliedFormat":1},{"version":"1ce14b81c5cc821994aa8ec1d42b220dd41b27fcc06373bce3958af7421b77d4","affectsGlobalScope":true,"impliedFormat":1},{"version":"b3a048b3e9302ef9a34ef4ebb9aecfb28b66abb3bce577206a79fee559c230da","affectsGlobalScope":true,"impliedFormat":1},{"version":"ef4a897cd2a3f91000c10264e400b3667c7e51e1b7365f03b62e8081dc53bde6","impliedFormat":1},{"version":"e4f06ed35b3c5f502e1d791bd88fdab795145fb0e8a4f4080c8775553b60b2d8","signature":"8efa3ceda4341b4edb6dc3e89d22baf53002b49ee38a513962c0a7d0c309bf59"},{"version":"d153a11543fd884b596587ccd97aebbeed950b26933ee000f94009f1ab142848","affectsGlobalScope":true,"impliedFormat":1},{"version":"0ccdaa19852d25ecd84eec365c3bfa16e7859cadecf6e9ca6d0dbbbee439743f","affectsGlobalScope":true,"impliedFormat":1},{"version":"cc2110f7decca6bfb9392e30421cfa1436479e4a6756e8fec6cbc22625d4f881","affectsGlobalScope":true,"impliedFormat":1},{"version":"096116f8fedc1765d5bd6ef360c257b4a9048e5415054b3bf3c41b07f8951b0b","affectsGlobalScope":true,"impliedFormat":1},{"version":"e5e01375c9e124a83b52ee4b3244ed1a4d214a6cfb54ac73e164a823a4a7860a","affectsGlobalScope":true,"impliedFormat":1},{"version":"f90ae2bbce1505e67f2f6502392e318f5714bae82d2d969185c4a6cecc8af2fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"4b58e207b93a8f1c88bbf2a95ddc686ac83962b13830fe8ad3f404ffc7051fb4","affectsGlobalScope":true,"impliedFormat":1},{"version":"1fefabcb2b06736a66d2904074d56268753654805e829989a46a0161cd8412c5","affectsGlobalScope":true,"impliedFormat":1},{"version":"9798340ffb0d067d69b1ae5b32faa17ab31b82466a3fc00d8f2f2df0c8554aaa","affectsGlobalScope":true,"impliedFormat":1},{"version":"c18a99f01eb788d849ad032b31cafd49de0b19e083fe775370834c5675d7df8e","affectsGlobalScope":true,"impliedFormat":1},{"version":"5247874c2a23b9a62d178ae84f2db6a1d54e6c9a2e7e057e178cc5eea13757fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"cdcf9ea426ad970f96ac930cd176d5c69c6c24eebd9fc580e1572d6c6a88f62c","impliedFormat":1},{"version":"23cd712e2ce083d68afe69224587438e5914b457b8acf87073c22494d706a3d0","impliedFormat":1},{"version":"156a859e21ef3244d13afeeba4e49760a6afa035c149dda52f0c45ea8903b338","impliedFormat":1},{"version":"10ec5e82144dfac6f04fa5d1d6c11763b3e4dbbac6d99101427219ab3e2ae887","impliedFormat":1},{"version":"615754924717c0b1e293e083b83503c0a872717ad5aa60ed7f1a699eb1b4ea5c","impliedFormat":1},{"version":"074de5b2fdead0165a2757e3aaef20f27a6347b1c36adea27d51456795b37682","impliedFormat":1},{"version":"68834d631c8838c715f225509cfc3927913b9cc7a4870460b5b60c8dbdb99baf","impliedFormat":1},{"version":"4137ebf04166f3a325f056aa56101adc75e9dceb30404a1844eb8604d89770e2","impliedFormat":1},{"version":"ccab02f3920fc75c01174c47fcf67882a11daf16baf9e81701d0a94636e94556","impliedFormat":1},{"version":"3e11fce78ad8c0e1d1db4ba5f0652285509be3acdd519529bc8fcef85f7dafd9","impliedFormat":1},{"version":"ea6bc8de8b59f90a7a3960005fd01988f98fd0784e14bc6922dde2e93305ec7d","impliedFormat":1},{"version":"36107995674b29284a115e21a0618c4c2751b32a8766dd4cb3ba740308b16d59","impliedFormat":1},{"version":"914a0ae30d96d71915fc519ccb4efbf2b62c0ddfb3a3fc6129151076bc01dc60","impliedFormat":1},{"version":"9c32412007b5662fd34a8eb04292fb5314ec370d7016d1c2fb8aa193c807fe22","impliedFormat":1},{"version":"7fd1b31fd35876b0aa650811c25ec2c97a3c6387e5473eb18004bed86cdd76b6","impliedFormat":1},{"version":"4d327f7d72ad0918275cea3eee49a6a8dc8114ae1d5b7f3f5d0774de75f7439a","impliedFormat":1},{"version":"6ebe8ebb8659aaa9d1acbf3710d7dae3e923e97610238b9511c25dc39023a166","impliedFormat":1},{"version":"e85d7f8068f6a26710bff0cc8c0fc5e47f71089c3780fbede05857331d2ddec9","impliedFormat":1},{"version":"7befaf0e76b5671be1d47b77fcc65f2b0aad91cc26529df1904f4a7c46d216e9","impliedFormat":1},{"version":"0a60a292b89ca7218b8616f78e5bbd1c96b87e048849469cccb4355e98af959a","impliedFormat":1},{"version":"0b6e25234b4eec6ed96ab138d96eb70b135690d7dd01f3dd8a8ab291c35a683a","impliedFormat":1},{"version":"9666f2f84b985b62400d2e5ab0adae9ff44de9b2a34803c2c5bd3c8325b17dc0","impliedFormat":1},{"version":"40cd35c95e9cf22cfa5bd84e96408b6fcbca55295f4ff822390abb11afbc3dca","impliedFormat":1},{"version":"b1616b8959bf557feb16369c6124a97a0e74ed6f49d1df73bb4b9ddf68acf3f3","impliedFormat":1},{"version":"5b03a034c72146b61573aab280f295b015b9168470f2df05f6080a2122f9b4df","impliedFormat":1},{"version":"40b463c6766ca1b689bfcc46d26b5e295954f32ad43e37ee6953c0a677e4ae2b","impliedFormat":1},{"version":"249b9cab7f5d628b71308c7d9bb0a808b50b091e640ba3ed6e2d0516f4a8d91d","impliedFormat":1},{"version":"80aae6afc67faa5ac0b32b5b8bc8cc9f7fa299cff15cf09cc2e11fd28c6ae29e","impliedFormat":1},{"version":"f473cd2288991ff3221165dcf73cd5d24da30391f87e85b3dd4d0450c787a391","impliedFormat":1},{"version":"499e5b055a5aba1e1998f7311a6c441a369831c70905cc565ceac93c28083d53","impliedFormat":1},{"version":"8aee8b6d4f9f62cf3776cda1305fb18763e2aade7e13cea5bbe699112df85214","impliedFormat":1},{"version":"98498b101803bb3dde9f76a56e65c14b75db1cc8bec5f4db72be541570f74fc5","impliedFormat":1},{"version":"1cc2a09e1a61a5222d4174ab358a9f9de5e906afe79dbf7363d871a7edda3955","impliedFormat":1},{"version":"5d0375ca7310efb77e3ef18d068d53784faf62705e0ad04569597ae0e755c401","impliedFormat":1},{"version":"59af37caec41ecf7b2e76059c9672a49e682c1a2aa6f9d7dc78878f53aa284d6","impliedFormat":1},{"version":"addf417b9eb3f938fddf8d81e96393a165e4be0d4a8b6402292f9c634b1cb00d","impliedFormat":1},{"version":"b64d4d1c5f877f9c666e98e833f0205edb9384acc46e98a1fef344f64d6aba44","impliedFormat":1},{"version":"adf27937dba6af9f08a68c5b1d3fce0ca7d4b960c57e6d6c844e7d1a8e53adae","impliedFormat":1},{"version":"12950411eeab8563b349cb7959543d92d8d02c289ed893d78499a19becb5a8cc","impliedFormat":1},{"version":"2e85db9e6fd73cfa3d7f28e0ab6b55417ea18931423bd47b409a96e4a169e8e6","impliedFormat":1},{"version":"c46e079fe54c76f95c67fb89081b3e399da2c7d109e7dca8e4b58d83e332e605","impliedFormat":1},{"version":"c9381908473a1c92cb8c516b184e75f4d226dad95c3a85a5af35f670064d9a2f","impliedFormat":1},{"version":"c3f5289820990ab66b70c7fb5b63cb674001009ff84b13de40619619a9c8175f","affectsGlobalScope":true,"impliedFormat":1},{"version":"b3275d55fac10b799c9546804126239baf020d220136163f763b55a74e50e750","affectsGlobalScope":true,"impliedFormat":1},{"version":"fa68a0a3b7cb32c00e39ee3cd31f8f15b80cac97dce51b6ee7fc14a1e8deb30b","affectsGlobalScope":true,"impliedFormat":1},{"version":"1cf059eaf468efcc649f8cf6075d3cb98e9a35a0fe9c44419ec3d2f5428d7123","affectsGlobalScope":true,"impliedFormat":1},{"version":"6c36e755bced82df7fb6ce8169265d0a7bb046ab4e2cb6d0da0cb72b22033e89","affectsGlobalScope":true,"impliedFormat":1},{"version":"e7721c4f69f93c91360c26a0a84ee885997d748237ef78ef665b153e622b36c1","affectsGlobalScope":true,"impliedFormat":1},{"version":"7a93de4ff8a63bafe62ba86b89af1df0ccb5e40bb85b0c67d6bbcfdcf96bf3d4","affectsGlobalScope":true,"impliedFormat":1},{"version":"90e85f9bc549dfe2b5749b45fe734144e96cd5d04b38eae244028794e142a77e","affectsGlobalScope":true,"impliedFormat":1},{"version":"e0a5deeb610b2a50a6350bd23df6490036a1773a8a71d70f2f9549ab009e67ee","affectsGlobalScope":true,"impliedFormat":1},{"version":"d2ae155afe8a01cc0ae612d99117cf8ef16692ba7c4366590156fdec1bcf2d8c","impliedFormat":1},{"version":"3f5e5d9be35913db9fea42a63f3df0b7e3c8703b97670a2125587b4dbbd56d7c","impliedFormat":1},{"version":"8caeb65fdc3bfe0d13f86f67324fcb2d858ed1c55f1f0cce892eb1acfb9f3239","impliedFormat":1},{"version":"57c23df0b5f7a8e26363a3849b0bc7763f6b241207157c8e40089d1df4116f35","affectsGlobalScope":true,"impliedFormat":1},{"version":"3b8bc0c17b54081b0878673989216229e575d67a10874e84566a21025a2461ee","impliedFormat":1},{"version":"5b0db5a58b73498792a29bfebc333438e61906fef75da898b410e24e52229e6f","impliedFormat":1},{"version":"dbe055b2b29a7bab2c1ca8f259436306adb43f469dca7e639a02cd3695d3f621","impliedFormat":1},{"version":"1678b04557dca52feab73cc67610918a7f5e25bfdba3e7fa081acd625d93106d","impliedFormat":1},{"version":"e3905f6902f0b69e5eefc230daa69fdd4ab707a973ec2d086d65af1b3ea47ef0","impliedFormat":1},{"version":"2ea729503db9793f2691162fec3dd1118cab62e96d025f8eeb376d43ec293395","impliedFormat":1},{"version":"9ec87fea42b92894b0f209931a880789d43c3397d09dd99c631ae40a2f7071d1","impliedFormat":1},{"version":"c68e88cdfadfb6c8ba5fc38e58a3a166b0beae77b1f05b7d921150a32a5ffb8d","impliedFormat":1},{"version":"2bc7aa4fba46df0bd495425a7c8201437a7d465f83854fac859df2d67f664df3","impliedFormat":1},{"version":"41d17e1ad9a002feb11c8cdd2777e5bbc0cdb1e3f595d237e4dded0b6949983b","impliedFormat":1},{"version":"07e4e61e946a9c15045539ecd5f5d2d02e7aab6fa82567826857e09cf0f37c2e","affectsGlobalScope":true,"impliedFormat":1},{"version":"1c4714ccc29149efb8777a1da0b04b8d2258f5d13ddbf4cd3c3d361fb531ac86","impliedFormat":1},{"version":"3ff275f84f89f8a7c0543da838f9da9614201abc4ce74c533029825adfb4433d","impliedFormat":1},{"version":"0eb5d0cbf09de5d34542b977fd6a933bb2e0817bffe8e1a541b2f1ad1b9af1ff","impliedFormat":1},{"version":"10deca769dfed888051b1808d6746f8883a490a707f8bdf9367079146987d6d0","impliedFormat":1},{"version":"2c2bdaa1d8ead9f68628d6d9d250e46ee8e81aa4898b4769a36956ae15e060fe","impliedFormat":1},{"version":"c32c840c62d8bd7aeb3147aa6754cd2d922b990a6b6634530cb2ebdce5adc8e9","impliedFormat":1},{"version":"e1c1a0b4d1ead0de9eca52203aeb1f771f21e6238d6fcd15aa56ac2a02f1b7bf","impliedFormat":1},{"version":"82b91e4e42e6c41bc7fc1b6c2dc5eba6a2ba98375eb1f210e6ff6bba2d54177e","impliedFormat":1},{"version":"6fe28249ac0c7bc19a79aa9264baf00efbd080e868dbe1d3052033ad1c64f206","affectsGlobalScope":true,"impliedFormat":1},{"version":"cbed824fec91efefc7bbdcb8b43d1a531fdbebd0e2ef19481501ff365a93cb70","impliedFormat":1},{"version":"8e9c23ba78aabc2e0a27033f18737a6df754067731e69dc5f52823957d60a4b6","impliedFormat":1},{"version":"d0716593b3f2b0451bcf0c24cfa86dec2235c325c89f201934248b7c742715fc","impliedFormat":1},{"version":"ec501101c2a96133a6c695f934c8f6642149cc728571b29cbb7b770984c1088e","impliedFormat":1},{"version":"b214ebcf76c51b115453f69729ee8aa7b7f8eccdae2a922b568a45c2d7ff52f7","impliedFormat":1},{"version":"429c9cdfa7d126255779efd7e6d9057ced2d69c81859bbab32073bad52e9ba76","impliedFormat":1},{"version":"2991bca2cc0f0628a278df2a2ccdb8d6cbcb700f3761abbed62bba137d5b1790","impliedFormat":1},{"version":"ce8653341224f8b45ff46d2a06f2cacb96f841f768a886c9d8dd8ec0878b11bd","affectsGlobalScope":true,"impliedFormat":1},{"version":"230763250f20449fa7b3c9273e1967adb0023dc890d4be1553faca658ee65971","impliedFormat":1},{"version":"c3e9078b60cb329d1221f5878e88cecfa3e74460550e605a58fcfb41a66029ff","impliedFormat":1},{"version":"a74edb3bab7394a9dbde529d60632be590def2f5f01024dbd85441587fbfbbe0","impliedFormat":1},{"version":"0ea59f7d3e51440baa64f429253759b106cfcbaf51e474cae606e02265b37cf8","impliedFormat":1},{"version":"bc18a1991ba681f03e13285fa1d7b99b03b67ee671b7bc936254467177543890","impliedFormat":1},{"version":"00049ccc87f3f37726db03c01ca68fe74fd9c0109b68c29eb9923ebec2c76b13","impliedFormat":1},{"version":"fa94bbf532b7af8f394b95fa310980d6e20bd2d4c871c6a6cb9f70f03750a44b","impliedFormat":1},{"version":"68d3f35108e2608b1f2f28b36d19d7055f31c4465cc5692cbd06c716a9fe7973","impliedFormat":1},{"version":"a6d543044570fbeed13a7f9925a868081cd2b14ef59cdd9da6ae76d41cab03d3","affectsGlobalScope":true,"impliedFormat":1},{"version":"7fa2214bb0d64701bc6f9ce8cde2fd2ff8c571e0b23065fa04a8a5a6beb91511","impliedFormat":1},{"version":"f1c93e046fb3d9b7f8249629f4b63dc068dd839b824dd0aa39a5e68476dc9420","impliedFormat":1},{"version":"016b29bf4926b80255a108c53a1451717350059da04fcae64d1075f5e93bbb39","impliedFormat":1},{"version":"841983e39bd4cbb463be385e92fda11057cab368bf27100a801c492f1d86cbaa","impliedFormat":1},{"version":"6f5383b3df1cdf4ff1aa7fb0850f77042b5786b5e65ec9a9b6be56ebfe4d9036","impliedFormat":1},{"version":"62fc21ed9ccbd83bd1166de277a4b5daaa8d15b5fa614c75610d20f3b73fba87","impliedFormat":1},{"version":"e4156ddb25aa0e3b5303d372f26957b36778f0f6bbd4326359269873295e3058","affectsGlobalScope":true,"impliedFormat":1},{"version":"cc1b433a84cae05ddc5672d4823170af78606ad21ecef60dbc4570190cbf1357","impliedFormat":1},{"version":"9d3821bc75c59577e52643324cec92fc2145642e8d17cf7ee07a3181f21d985d","impliedFormat":1},{"version":"7f78cfb2b343838612c192cb251746e3a7c62ac7675726a47e130d9b213f6580","impliedFormat":1},{"version":"201db9cf1687fab1adf5282fcba861f382b32303dc4f67c89d59655e78a25461","impliedFormat":1},{"version":"c77fb31bc17fd241d3922a9f88c59e3361cdf76d1328ba9412fc6bf7310b638d","impliedFormat":1},{"version":"0a20eaf2e4b1e3c1e1f87f7bccb0c936375b23b022baeea750519b7c9bc6ce83","impliedFormat":1},{"version":"b484ec11ba00e3a2235562a41898d55372ccabe607986c6fa4f4aba72093749f","impliedFormat":1},{"version":"a16b91b27bd6b706c687c88cbc8a7d4ee98e5ed6043026d6b84bda923c0aed67","impliedFormat":1},{"version":"694b812e0ed11285e8822cf8131e3ce7083a500b3b1d185fff9ed1089677bd0a","impliedFormat":1},{"version":"99ab6d0d660ce4d21efb52288a39fd35bb3f556980ec5463b1ae8f304a3bbc85","impliedFormat":1},{"version":"6eeded8c7e352be6e0efb83f4935ec752513c4d22043b52522b90849a49a3a11","impliedFormat":1},{"version":"6c1ad90050ffbb151cacc68e2d06ea1a26a945659391e32651f5d42b86fd7f2c","impliedFormat":1},{"version":"55cdbeebe76a1fa18bbd7e7bf73350a2173926bd3085bb050cf5a5397025ee4e","impliedFormat":1}],"root":[94],"options":{"allowImportingTsExtensions":false,"composite":true,"declaration":true,"declarationDir":"./types","experimentalDecorators":true,"module":99,"outDir":"./esm","rootDir":"../src","skipLibCheck":true,"strict":true,"target":99},"referencedMap":[[157,1],[158,1],[159,2],[97,3],[160,4],[161,5],[162,6],[95,7],[163,8],[164,9],[165,10],[166,11],[167,12],[168,13],[169,13],[170,14],[171,15],[172,16],[173,17],[98,7],[96,7],[174,18],[175,19],[176,20],[217,21],[177,22],[178,23],[179,22],[180,24],[181,25],[183,26],[184,27],[185,27],[186,27],[187,28],[188,29],[189,30],[190,31],[191,32],[192,33],[193,33],[194,34],[195,7],[196,7],[197,35],[198,36],[199,35],[200,37],[201,38],[202,39],[203,40],[204,41],[205,42],[206,43],[207,44],[208,45],[209,46],[210,47],[211,48],[212,49],[213,50],[214,51],[99,22],[100,7],[101,52],[102,53],[103,7],[104,54],[105,7],[148,55],[149,56],[150,57],[151,57],[152,58],[153,7],[154,4],[155,59],[156,56],[215,60],[216,61],[182,7],[91,7],[92,7],[16,7],[14,7],[15,7],[20,7],[19,7],[2,7],[21,7],[22,7],[23,7],[24,7],[25,7],[26,7],[27,7],[28,7],[3,7],[29,7],[30,7],[4,7],[31,7],[35,7],[32,7],[33,7],[34,7],[36,7],[37,7],[38,7],[5,7],[39,7],[40,7],[41,7],[42,7],[6,7],[46,7],[43,7],[44,7],[45,7],[47,7],[7,7],[48,7],[53,7],[54,7],[49,7],[50,7],[51,7],[52,7],[8,7],[58,7],[55,7],[56,7],[57,7],[59,7],[9,7],[60,7],[61,7],[62,7],[64,7],[63,7],[65,7],[66,7],[10,7],[67,7],[68,7],[69,7],[11,7],[70,7],[71,7],[72,7],[73,7],[74,7],[75,7],[12,7],[76,7],[77,7],[78,7],[79,7],[80,7],[1,7],[81,7],[82,7],[13,7],[83,7],[84,7],[85,7],[86,7],[93,7],[87,7],[88,7],[89,7],[90,7],[18,7],[17,7],[124,62],[136,63],[121,64],[137,65],[146,66],[112,67],[113,68],[111,69],[145,70],[140,71],[144,72],[115,73],[133,74],[114,75],[143,76],[109,77],[110,71],[116,78],[117,7],[123,79],[120,78],[107,80],[147,81],[138,82],[127,83],[126,78],[128,84],[131,85],[125,86],[129,87],[141,70],[118,88],[119,89],[132,90],[108,65],[135,91],[134,78],[122,89],[130,92],[139,7],[106,7],[142,93],[94,27]],"latestChangedDtsFile":"./types/index.d.ts","version":"6.0.3"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { join, dirname } from 'node:path';
|
|
2
|
+
export interface WorkspaceManifest {
|
|
3
|
+
name?: string;
|
|
4
|
+
version?: string;
|
|
5
|
+
private?: boolean;
|
|
6
|
+
dependencies?: Record<string, string>;
|
|
7
|
+
devDependencies?: Record<string, string>;
|
|
8
|
+
peerDependencies?: Record<string, string>;
|
|
9
|
+
optionalDependencies?: Record<string, string>;
|
|
10
|
+
workspaces?: string[] | {
|
|
11
|
+
packages?: string[];
|
|
12
|
+
nohoist?: string[];
|
|
13
|
+
};
|
|
14
|
+
[key: string]: unknown;
|
|
15
|
+
}
|
|
16
|
+
export interface Workspace {
|
|
17
|
+
/** Absolute path of the workspace directory. */
|
|
18
|
+
location: string;
|
|
19
|
+
/** Workspace-relative location (e.g. `packages/infra/cli`). */
|
|
20
|
+
relativeLocation: string;
|
|
21
|
+
/** `<name>` from package.json — required for resolving `workspace:^`. */
|
|
22
|
+
name: string;
|
|
23
|
+
/** `<version>` from package.json — used to substitute `workspace:^`. */
|
|
24
|
+
version: string;
|
|
25
|
+
/** Loaded package.json contents (manifest). */
|
|
26
|
+
manifest: WorkspaceManifest;
|
|
27
|
+
/** `private: true` packages are excluded by `--no-private`. */
|
|
28
|
+
private: boolean;
|
|
29
|
+
}
|
|
30
|
+
export interface DiscoverWorkspacesOptions {
|
|
31
|
+
/** Override the patterns read from the root package.json. */
|
|
32
|
+
patterns?: string[];
|
|
33
|
+
/**
|
|
34
|
+
* Include the root package as a workspace itself. Yarn does not do this
|
|
35
|
+
* by default; we keep the same behavior unless the caller opts in.
|
|
36
|
+
*/
|
|
37
|
+
includeRoot?: boolean;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Read `<root>/package.json` and walk its `workspaces` glob patterns. Returns
|
|
41
|
+
* the full set of workspaces with their parsed manifests. Throws if the root
|
|
42
|
+
* package.json is missing or malformed; silently skips glob-matched dirs
|
|
43
|
+
* that don't have a package.json (matches yarn's behavior).
|
|
44
|
+
*/
|
|
45
|
+
export declare function discoverWorkspaces(root: string, options?: DiscoverWorkspacesOptions): Workspace[];
|
|
46
|
+
/**
|
|
47
|
+
* Resolve a `workspace:`-protocol descriptor against the discovered
|
|
48
|
+
* workspaces. Accepts the common shapes yarn 4 supports:
|
|
49
|
+
*
|
|
50
|
+
* `workspace:^` → caret-range of the workspace's current version
|
|
51
|
+
* `workspace:~` → tilde-range
|
|
52
|
+
* `workspace:*` → exact version (matches yarn's `workspace:*` semantics)
|
|
53
|
+
* `workspace:<ver>` → explicit range, returned as-is (yarn's `workspace:^1.2.3`)
|
|
54
|
+
*
|
|
55
|
+
* Returns the resolved spec (e.g. `^0.3.21`) — what would land in
|
|
56
|
+
* `node_modules/<dep>/package.json` after `yarn install`. Returns `undefined`
|
|
57
|
+
* when the spec isn't a workspace-protocol value (caller falls back to the
|
|
58
|
+
* external resolver).
|
|
59
|
+
*/
|
|
60
|
+
export declare function resolveWorkspaceProtocol(spec: string, pkgName: string, workspaces: ReadonlyMap<string, Workspace> | readonly Workspace[]): string | undefined;
|
|
61
|
+
export interface DependencyGraph {
|
|
62
|
+
/** Adjacency list: workspace name → set of workspace names it depends on. */
|
|
63
|
+
edges: Map<string, Set<string>>;
|
|
64
|
+
/** Workspaces indexed by name for fast lookup by callers. */
|
|
65
|
+
byName: Map<string, Workspace>;
|
|
66
|
+
}
|
|
67
|
+
export interface BuildGraphOptions {
|
|
68
|
+
/**
|
|
69
|
+
* Include `devDependencies` in the edge set. Default `false` — matches
|
|
70
|
+
* yarn's `--topological` flag (which only counts production deps).
|
|
71
|
+
* `yarn workspaces foreach --topological-dev` is the opt-in for the
|
|
72
|
+
* dev-graph (which is often cyclic in real monorepos, including
|
|
73
|
+
* gjsify itself — `@gjsify/utils` devDep on `@gjsify/cli` creates a
|
|
74
|
+
* cycle when traced through `@gjsify/cli`'s prod deps).
|
|
75
|
+
*/
|
|
76
|
+
includeDev?: boolean;
|
|
77
|
+
/** Include peerDependencies. Default `false` — yarn treats peers as constraint-only. */
|
|
78
|
+
includePeer?: boolean;
|
|
79
|
+
/** Include optionalDependencies. Default `true`. */
|
|
80
|
+
includeOptional?: boolean;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Build the inter-workspace dependency graph. Each edge `A → B` means "A
|
|
84
|
+
* declares a `workspace:`-protocol entry pointing at B". External deps
|
|
85
|
+
* (registry packages) are not represented — this graph is the input for
|
|
86
|
+
* `topologicalSort` (build order) and `--topological` in `gjsify foreach`.
|
|
87
|
+
*/
|
|
88
|
+
export declare function buildDependencyGraph(workspaces: readonly Workspace[], options?: BuildGraphOptions): DependencyGraph;
|
|
89
|
+
/**
|
|
90
|
+
* Kahn's algorithm: returns workspaces in topological build order, so each
|
|
91
|
+
* workspace appears after all of its inter-workspace dependencies. Throws
|
|
92
|
+
* on cycle — yarn's `workspaces foreach --topological` does the same.
|
|
93
|
+
*/
|
|
94
|
+
export declare function topologicalSort(graph: DependencyGraph): Workspace[];
|
|
95
|
+
/**
|
|
96
|
+
* Filter workspaces by glob-pattern include/exclude (mirrors
|
|
97
|
+
* `yarn workspaces foreach --include '@gjsify/example-*' --exclude
|
|
98
|
+
* '@gjsify/example-*-net'` shape). Uses a minimal glob: only `*` is
|
|
99
|
+
* supported (matches any non-`/` segment). That covers every pattern the
|
|
100
|
+
* gjsify monorepo + ts-for-gir actually use.
|
|
101
|
+
*/
|
|
102
|
+
export declare function filterWorkspaces(workspaces: readonly Workspace[], options: {
|
|
103
|
+
include?: readonly string[];
|
|
104
|
+
exclude?: readonly string[];
|
|
105
|
+
noPrivate?: boolean;
|
|
106
|
+
}): Workspace[];
|
|
107
|
+
export { join as joinPath, dirname as dirnamePath };
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@gjsify/workspace",
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "Yarn-workspaces-compatible discovery + resolution for gjsify install/foreach. Reads package.json `workspaces` (string array or { packages, nohoist } shape), expands globs, resolves `workspace:^` to local versions, builds the dependency graph + topological order. Cross-platform Node + GJS.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"module": "lib/esm/index.js",
|
|
7
|
+
"main": "lib/esm/index.js",
|
|
8
|
+
"types": "lib/types/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./lib/types/index.d.ts",
|
|
12
|
+
"default": "./lib/esm/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"scripts": {
|
|
16
|
+
"clear": "rm -rf lib tsconfig.tsbuildinfo test.gjs.mjs test.node.mjs || exit 0",
|
|
17
|
+
"check": "tsc --noEmit",
|
|
18
|
+
"build": "yarn build:gjsify && yarn build:types",
|
|
19
|
+
"build:gjsify": "gjsify build --library 'src/**/*.{ts,js}' --exclude 'src/**/*.spec.{mts,ts}' 'src/test.mts'",
|
|
20
|
+
"build:types": "tsc -p tsconfig.build.json",
|
|
21
|
+
"build:test": "yarn build:test:gjs && yarn build:test:node",
|
|
22
|
+
"build:test:gjs": "gjsify build src/test.mts --app gjs --outfile test.gjs.mjs",
|
|
23
|
+
"build:test:node": "gjsify build src/test.mts --app node --outfile test.node.mjs",
|
|
24
|
+
"test": "yarn build:gjsify && yarn build:test && yarn test:node && yarn test:gjs",
|
|
25
|
+
"test:gjs": "gjsify run test.gjs.mjs",
|
|
26
|
+
"test:node": "node test.node.mjs"
|
|
27
|
+
},
|
|
28
|
+
"keywords": [
|
|
29
|
+
"gjs",
|
|
30
|
+
"node",
|
|
31
|
+
"workspace",
|
|
32
|
+
"yarn",
|
|
33
|
+
"monorepo",
|
|
34
|
+
"install"
|
|
35
|
+
],
|
|
36
|
+
"license": "MIT",
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@gjsify/cli": "^0.4.0",
|
|
39
|
+
"@gjsify/unit": "^0.4.0",
|
|
40
|
+
"@types/node": "^25.6.2",
|
|
41
|
+
"typescript": "^6.0.3"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
// @gjsify/workspace specs — Yarn-workspaces-compatible discovery + graph.
|
|
2
|
+
//
|
|
3
|
+
// Test workspaces live under `node:fs.mkdtempSync` so the suite is fully
|
|
4
|
+
// hermetic. Each test builds a fresh fixture, validates the public API,
|
|
5
|
+
// then cleans up.
|
|
6
|
+
|
|
7
|
+
import { describe, it, expect } from '@gjsify/unit';
|
|
8
|
+
import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from 'node:fs';
|
|
9
|
+
import { tmpdir } from 'node:os';
|
|
10
|
+
import { join } from 'node:path';
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
discoverWorkspaces,
|
|
14
|
+
resolveWorkspaceProtocol,
|
|
15
|
+
buildDependencyGraph,
|
|
16
|
+
topologicalSort,
|
|
17
|
+
filterWorkspaces,
|
|
18
|
+
type Workspace,
|
|
19
|
+
} from './index.js';
|
|
20
|
+
|
|
21
|
+
function makeFixture(layout: Record<string, Record<string, unknown>>): string {
|
|
22
|
+
const root = mkdtempSync(join(tmpdir(), 'gjsify-workspace-spec-'));
|
|
23
|
+
for (const [relPath, manifest] of Object.entries(layout)) {
|
|
24
|
+
const dir = join(root, relPath);
|
|
25
|
+
mkdirSync(dir, { recursive: true });
|
|
26
|
+
writeFileSync(join(dir, 'package.json'), JSON.stringify(manifest) + '\n');
|
|
27
|
+
}
|
|
28
|
+
return root;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export default async (): Promise<void> => {
|
|
32
|
+
await describe('@gjsify/workspace', async () => {
|
|
33
|
+
await describe('discoverWorkspaces', async () => {
|
|
34
|
+
await it('expands `packages/*` glob + reads manifests', () => {
|
|
35
|
+
const root = makeFixture({
|
|
36
|
+
'.': { name: 'root', version: '0.1.0', private: true, workspaces: ['packages/*'] },
|
|
37
|
+
'packages/a': { name: 'pkg-a', version: '1.0.0' },
|
|
38
|
+
'packages/b': { name: 'pkg-b', version: '2.0.0' },
|
|
39
|
+
});
|
|
40
|
+
try {
|
|
41
|
+
const ws = discoverWorkspaces(root);
|
|
42
|
+
expect(ws.length).toBe(2);
|
|
43
|
+
expect(ws.map((w) => w.name).sort()).toStrictEqual(['pkg-a', 'pkg-b']);
|
|
44
|
+
const a = ws.find((w) => w.name === 'pkg-a')!;
|
|
45
|
+
expect(a.version).toBe('1.0.0');
|
|
46
|
+
expect(a.relativeLocation).toBe('packages/a');
|
|
47
|
+
} finally { rmSync(root, { recursive: true, force: true }); }
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
await it('handles `{ packages: [...] }` shape (yarn classic)', () => {
|
|
51
|
+
const root = makeFixture({
|
|
52
|
+
'.': { name: 'root', private: true, workspaces: { packages: ['libs/*'] } },
|
|
53
|
+
'libs/x': { name: 'x', version: '0.0.1' },
|
|
54
|
+
});
|
|
55
|
+
try {
|
|
56
|
+
const ws = discoverWorkspaces(root);
|
|
57
|
+
expect(ws.length).toBe(1);
|
|
58
|
+
expect(ws[0]?.name).toBe('x');
|
|
59
|
+
} finally { rmSync(root, { recursive: true, force: true }); }
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
await it('skips dirs without package.json', () => {
|
|
63
|
+
const root = makeFixture({
|
|
64
|
+
'.': { name: 'root', private: true, workspaces: ['packages/*'] },
|
|
65
|
+
'packages/with-manifest': { name: 'good', version: '0.1.0' },
|
|
66
|
+
});
|
|
67
|
+
// Add a sibling dir without a package.json.
|
|
68
|
+
mkdirSync(join(root, 'packages', 'no-manifest'), { recursive: true });
|
|
69
|
+
try {
|
|
70
|
+
const ws = discoverWorkspaces(root);
|
|
71
|
+
expect(ws.length).toBe(1);
|
|
72
|
+
expect(ws[0]?.name).toBe('good');
|
|
73
|
+
} finally { rmSync(root, { recursive: true, force: true }); }
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
await it('flags `private: true` workspaces correctly', () => {
|
|
77
|
+
const root = makeFixture({
|
|
78
|
+
'.': { name: 'root', private: true, workspaces: ['packages/*'] },
|
|
79
|
+
'packages/pub': { name: 'pub', version: '0.1.0' },
|
|
80
|
+
'packages/priv': { name: 'priv', version: '0.1.0', private: true },
|
|
81
|
+
});
|
|
82
|
+
try {
|
|
83
|
+
const ws = discoverWorkspaces(root);
|
|
84
|
+
const pub = ws.find((w) => w.name === 'pub')!;
|
|
85
|
+
const priv = ws.find((w) => w.name === 'priv')!;
|
|
86
|
+
expect(pub.private).toBeFalsy();
|
|
87
|
+
expect(priv.private).toBe(true);
|
|
88
|
+
} finally { rmSync(root, { recursive: true, force: true }); }
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
await describe('resolveWorkspaceProtocol', async () => {
|
|
93
|
+
const ws: Workspace[] = [
|
|
94
|
+
makeWs('@gjsify/core', '1.2.3'),
|
|
95
|
+
makeWs('@gjsify/util', '0.4.0'),
|
|
96
|
+
];
|
|
97
|
+
|
|
98
|
+
await it('expands workspace:^ to caret-range', () => {
|
|
99
|
+
expect(resolveWorkspaceProtocol('workspace:^', '@gjsify/core', ws)).toBe('^1.2.3');
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
await it('expands workspace:~ to tilde-range', () => {
|
|
103
|
+
expect(resolveWorkspaceProtocol('workspace:~', '@gjsify/util', ws)).toBe('~0.4.0');
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
await it('expands workspace:* to exact version', () => {
|
|
107
|
+
expect(resolveWorkspaceProtocol('workspace:*', '@gjsify/core', ws)).toBe('1.2.3');
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
await it('passes explicit ranges through', () => {
|
|
111
|
+
expect(resolveWorkspaceProtocol('workspace:^1.0.0', '@gjsify/core', ws)).toBe('^1.0.0');
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
await it('returns undefined for non-workspace specs', () => {
|
|
115
|
+
expect(resolveWorkspaceProtocol('^1.0.0', '@gjsify/core', ws)).toBeUndefined();
|
|
116
|
+
expect(resolveWorkspaceProtocol('latest', '@gjsify/core', ws)).toBeUndefined();
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
await it('throws when the workspace does not exist locally', () => {
|
|
120
|
+
expect(() => resolveWorkspaceProtocol('workspace:^', '@unknown/pkg', ws)).toThrow();
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
await describe('buildDependencyGraph + topologicalSort', async () => {
|
|
125
|
+
await it('only records inter-workspace edges (ignores external deps)', () => {
|
|
126
|
+
const ws: Workspace[] = [
|
|
127
|
+
makeWs('a', '1.0.0', { dependencies: { b: 'workspace:^', lodash: '^4.0.0' } }),
|
|
128
|
+
makeWs('b', '1.0.0'),
|
|
129
|
+
];
|
|
130
|
+
const g = buildDependencyGraph(ws);
|
|
131
|
+
expect(g.edges.get('a')!.has('b')).toBe(true);
|
|
132
|
+
expect(g.edges.get('a')!.has('lodash')).toBeFalsy();
|
|
133
|
+
expect(g.edges.get('b')!.size).toBe(0);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
await it('excludes devDependencies by default (yarn --topological)', () => {
|
|
137
|
+
const ws: Workspace[] = [
|
|
138
|
+
makeWs('lib', '1.0.0', { dependencies: { core: 'workspace:^' }, devDependencies: { tooling: 'workspace:^' } }),
|
|
139
|
+
makeWs('core', '1.0.0'),
|
|
140
|
+
makeWs('tooling', '1.0.0'),
|
|
141
|
+
];
|
|
142
|
+
const def = buildDependencyGraph(ws);
|
|
143
|
+
expect(def.edges.get('lib')!.has('core')).toBe(true);
|
|
144
|
+
expect(def.edges.get('lib')!.has('tooling')).toBeFalsy();
|
|
145
|
+
const withDev = buildDependencyGraph(ws, { includeDev: true });
|
|
146
|
+
expect(withDev.edges.get('lib')!.has('tooling')).toBe(true);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
await it('topologicalSort puts dependencies BEFORE dependents', () => {
|
|
150
|
+
const ws: Workspace[] = [
|
|
151
|
+
makeWs('app', '1.0.0', { dependencies: { lib: 'workspace:^', utils: 'workspace:^' } }),
|
|
152
|
+
makeWs('lib', '1.0.0', { dependencies: { utils: 'workspace:^' } }),
|
|
153
|
+
makeWs('utils', '1.0.0'),
|
|
154
|
+
];
|
|
155
|
+
const g = buildDependencyGraph(ws);
|
|
156
|
+
const sorted = topologicalSort(g);
|
|
157
|
+
const order = sorted.map((w) => w.name);
|
|
158
|
+
// `utils` must come before `lib` and `app`. `lib` must come before `app`.
|
|
159
|
+
expect(order.indexOf('utils') < order.indexOf('lib')).toBe(true);
|
|
160
|
+
expect(order.indexOf('lib') < order.indexOf('app')).toBe(true);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
await it('throws on cycle', () => {
|
|
164
|
+
const ws: Workspace[] = [
|
|
165
|
+
makeWs('a', '1.0.0', { dependencies: { b: 'workspace:^' } }),
|
|
166
|
+
makeWs('b', '1.0.0', { dependencies: { a: 'workspace:^' } }),
|
|
167
|
+
];
|
|
168
|
+
const g = buildDependencyGraph(ws);
|
|
169
|
+
expect(() => topologicalSort(g)).toThrow();
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
await describe('filterWorkspaces', async () => {
|
|
174
|
+
const ws: Workspace[] = [
|
|
175
|
+
makeWs('@gjsify/cli', '0.3.0'),
|
|
176
|
+
makeWs('@gjsify/example-foo', '0.1.0'),
|
|
177
|
+
makeWs('@gjsify/example-bar', '0.1.0'),
|
|
178
|
+
makeWs('@girs/glib-2.0', '0.0.0', undefined, /* private */ true),
|
|
179
|
+
];
|
|
180
|
+
|
|
181
|
+
await it('--include glob picks matching workspaces', () => {
|
|
182
|
+
const sel = filterWorkspaces(ws, { include: ['@gjsify/example-*'] });
|
|
183
|
+
expect(sel.length).toBe(2);
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
await it('--exclude removes matching workspaces', () => {
|
|
187
|
+
const sel = filterWorkspaces(ws, { exclude: ['@girs/*'] });
|
|
188
|
+
expect(sel.length).toBe(3);
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
await it('--no-private drops private workspaces', () => {
|
|
192
|
+
const sel = filterWorkspaces(ws, { noPrivate: true });
|
|
193
|
+
expect(sel.find((w) => w.name === '@girs/glib-2.0')).toBeUndefined();
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
function makeWs(
|
|
200
|
+
name: string,
|
|
201
|
+
version: string,
|
|
202
|
+
manifest: Partial<Workspace['manifest']> = {},
|
|
203
|
+
priv = false,
|
|
204
|
+
): Workspace {
|
|
205
|
+
return {
|
|
206
|
+
location: `/tmp/synthetic/${name}`,
|
|
207
|
+
relativeLocation: name,
|
|
208
|
+
name,
|
|
209
|
+
version,
|
|
210
|
+
private: priv,
|
|
211
|
+
manifest: { name, version, ...manifest },
|
|
212
|
+
};
|
|
213
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
// @gjsify/workspace — Yarn-workspaces-compatible monorepo discovery + resolution.
|
|
2
|
+
//
|
|
3
|
+
// Implements the parts of the yarn workspaces surface that `gjsify install`
|
|
4
|
+
// and `gjsify foreach` actually need (see AGENTS.md "yarn replacement"):
|
|
5
|
+
// 1. `discoverWorkspaces(root)` reads `<root>/package.json` `workspaces`,
|
|
6
|
+
// expands the glob patterns (`packages/*`, `tests/integration/*`, …)
|
|
7
|
+
// against the on-disk tree, parses each workspace's package.json,
|
|
8
|
+
// returns the full Workspace[] list.
|
|
9
|
+
// 2. `resolveWorkspaceProtocol(spec, workspaces)` turns a `workspace:^`
|
|
10
|
+
// or `workspace:*` descriptor into the resolved version of the
|
|
11
|
+
// matching local workspace — that's the "intra-monorepo dep link"
|
|
12
|
+
// yarn install does for every `workspace:^` in 60+ workspaces.
|
|
13
|
+
// 3. `buildDependencyGraph(workspaces)` returns adjacency lists for the
|
|
14
|
+
// workspaces. Only inter-workspace edges are recorded (external
|
|
15
|
+
// registry deps are out of scope for this graph).
|
|
16
|
+
// 4. `topologicalSort(graph)` returns the workspaces in build order —
|
|
17
|
+
// `--topological` flag in `gjsify foreach`. Uses Kahn's algorithm.
|
|
18
|
+
//
|
|
19
|
+
// All four functions are pure Node-built-ins + JSON; works under Node and
|
|
20
|
+
// GJS without bindings. The CLI consumes this package via D.3-D.5.
|
|
21
|
+
|
|
22
|
+
import { readFileSync, readdirSync, statSync, existsSync } from 'node:fs';
|
|
23
|
+
import { join, resolve, relative, sep, dirname } from 'node:path';
|
|
24
|
+
|
|
25
|
+
export interface WorkspaceManifest {
|
|
26
|
+
name?: string;
|
|
27
|
+
version?: string;
|
|
28
|
+
private?: boolean;
|
|
29
|
+
dependencies?: Record<string, string>;
|
|
30
|
+
devDependencies?: Record<string, string>;
|
|
31
|
+
peerDependencies?: Record<string, string>;
|
|
32
|
+
optionalDependencies?: Record<string, string>;
|
|
33
|
+
workspaces?: string[] | { packages?: string[]; nohoist?: string[] };
|
|
34
|
+
[key: string]: unknown;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface Workspace {
|
|
38
|
+
/** Absolute path of the workspace directory. */
|
|
39
|
+
location: string;
|
|
40
|
+
/** Workspace-relative location (e.g. `packages/infra/cli`). */
|
|
41
|
+
relativeLocation: string;
|
|
42
|
+
/** `<name>` from package.json — required for resolving `workspace:^`. */
|
|
43
|
+
name: string;
|
|
44
|
+
/** `<version>` from package.json — used to substitute `workspace:^`. */
|
|
45
|
+
version: string;
|
|
46
|
+
/** Loaded package.json contents (manifest). */
|
|
47
|
+
manifest: WorkspaceManifest;
|
|
48
|
+
/** `private: true` packages are excluded by `--no-private`. */
|
|
49
|
+
private: boolean;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface DiscoverWorkspacesOptions {
|
|
53
|
+
/** Override the patterns read from the root package.json. */
|
|
54
|
+
patterns?: string[];
|
|
55
|
+
/**
|
|
56
|
+
* Include the root package as a workspace itself. Yarn does not do this
|
|
57
|
+
* by default; we keep the same behavior unless the caller opts in.
|
|
58
|
+
*/
|
|
59
|
+
includeRoot?: boolean;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Read `<root>/package.json` and walk its `workspaces` glob patterns. Returns
|
|
64
|
+
* the full set of workspaces with their parsed manifests. Throws if the root
|
|
65
|
+
* package.json is missing or malformed; silently skips glob-matched dirs
|
|
66
|
+
* that don't have a package.json (matches yarn's behavior).
|
|
67
|
+
*/
|
|
68
|
+
export function discoverWorkspaces(
|
|
69
|
+
root: string,
|
|
70
|
+
options: DiscoverWorkspacesOptions = {},
|
|
71
|
+
): Workspace[] {
|
|
72
|
+
const rootManifestPath = join(root, 'package.json');
|
|
73
|
+
if (!existsSync(rootManifestPath)) {
|
|
74
|
+
throw new Error(`@gjsify/workspace: no package.json at ${root}`);
|
|
75
|
+
}
|
|
76
|
+
const rootManifest = JSON.parse(readFileSync(rootManifestPath, 'utf-8')) as WorkspaceManifest;
|
|
77
|
+
const patterns = options.patterns ?? extractWorkspacePatterns(rootManifest);
|
|
78
|
+
|
|
79
|
+
const out: Workspace[] = [];
|
|
80
|
+
if (options.includeRoot && rootManifest.name) {
|
|
81
|
+
out.push({
|
|
82
|
+
location: root,
|
|
83
|
+
relativeLocation: '.',
|
|
84
|
+
name: rootManifest.name,
|
|
85
|
+
version: rootManifest.version ?? '0.0.0',
|
|
86
|
+
manifest: rootManifest,
|
|
87
|
+
private: rootManifest.private === true,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
for (const pattern of patterns) {
|
|
92
|
+
for (const matchedDir of expandPattern(root, pattern)) {
|
|
93
|
+
const pkgPath = join(matchedDir, 'package.json');
|
|
94
|
+
if (!existsSync(pkgPath)) continue;
|
|
95
|
+
let manifest: WorkspaceManifest;
|
|
96
|
+
try {
|
|
97
|
+
manifest = JSON.parse(readFileSync(pkgPath, 'utf-8')) as WorkspaceManifest;
|
|
98
|
+
} catch {
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
if (!manifest.name) continue;
|
|
102
|
+
out.push({
|
|
103
|
+
location: matchedDir,
|
|
104
|
+
relativeLocation: relative(root, matchedDir).split(sep).join('/'),
|
|
105
|
+
name: manifest.name,
|
|
106
|
+
version: manifest.version ?? '0.0.0',
|
|
107
|
+
manifest,
|
|
108
|
+
private: manifest.private === true,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Deterministic order — yarn sorts by anchored locator hash; we sort by
|
|
114
|
+
// relative location which is stable across machines and reproducible
|
|
115
|
+
// for diffing.
|
|
116
|
+
out.sort((a, b) => a.relativeLocation.localeCompare(b.relativeLocation));
|
|
117
|
+
return out;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Resolve a `workspace:`-protocol descriptor against the discovered
|
|
122
|
+
* workspaces. Accepts the common shapes yarn 4 supports:
|
|
123
|
+
*
|
|
124
|
+
* `workspace:^` → caret-range of the workspace's current version
|
|
125
|
+
* `workspace:~` → tilde-range
|
|
126
|
+
* `workspace:*` → exact version (matches yarn's `workspace:*` semantics)
|
|
127
|
+
* `workspace:<ver>` → explicit range, returned as-is (yarn's `workspace:^1.2.3`)
|
|
128
|
+
*
|
|
129
|
+
* Returns the resolved spec (e.g. `^0.3.21`) — what would land in
|
|
130
|
+
* `node_modules/<dep>/package.json` after `yarn install`. Returns `undefined`
|
|
131
|
+
* when the spec isn't a workspace-protocol value (caller falls back to the
|
|
132
|
+
* external resolver).
|
|
133
|
+
*/
|
|
134
|
+
export function resolveWorkspaceProtocol(
|
|
135
|
+
spec: string,
|
|
136
|
+
pkgName: string,
|
|
137
|
+
workspaces: ReadonlyMap<string, Workspace> | readonly Workspace[],
|
|
138
|
+
): string | undefined {
|
|
139
|
+
if (!spec.startsWith('workspace:')) return undefined;
|
|
140
|
+
const value = spec.slice('workspace:'.length);
|
|
141
|
+
const map: ReadonlyMap<string, Workspace> = workspaces instanceof Map
|
|
142
|
+
? workspaces
|
|
143
|
+
: indexByName(workspaces as readonly Workspace[]);
|
|
144
|
+
const target = map.get(pkgName);
|
|
145
|
+
if (!target) {
|
|
146
|
+
throw new Error(
|
|
147
|
+
`@gjsify/workspace: workspace dep "${pkgName}" referenced as "${spec}" but no workspace ` +
|
|
148
|
+
`with that name was discovered`,
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
const version = target.version;
|
|
152
|
+
if (value === '^') return `^${version}`;
|
|
153
|
+
if (value === '~') return `~${version}`;
|
|
154
|
+
if (value === '*') return version;
|
|
155
|
+
// Explicit range: pass through.
|
|
156
|
+
return value;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export interface DependencyGraph {
|
|
160
|
+
/** Adjacency list: workspace name → set of workspace names it depends on. */
|
|
161
|
+
edges: Map<string, Set<string>>;
|
|
162
|
+
/** Workspaces indexed by name for fast lookup by callers. */
|
|
163
|
+
byName: Map<string, Workspace>;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export interface BuildGraphOptions {
|
|
167
|
+
/**
|
|
168
|
+
* Include `devDependencies` in the edge set. Default `false` — matches
|
|
169
|
+
* yarn's `--topological` flag (which only counts production deps).
|
|
170
|
+
* `yarn workspaces foreach --topological-dev` is the opt-in for the
|
|
171
|
+
* dev-graph (which is often cyclic in real monorepos, including
|
|
172
|
+
* gjsify itself — `@gjsify/utils` devDep on `@gjsify/cli` creates a
|
|
173
|
+
* cycle when traced through `@gjsify/cli`'s prod deps).
|
|
174
|
+
*/
|
|
175
|
+
includeDev?: boolean;
|
|
176
|
+
/** Include peerDependencies. Default `false` — yarn treats peers as constraint-only. */
|
|
177
|
+
includePeer?: boolean;
|
|
178
|
+
/** Include optionalDependencies. Default `true`. */
|
|
179
|
+
includeOptional?: boolean;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Build the inter-workspace dependency graph. Each edge `A → B` means "A
|
|
184
|
+
* declares a `workspace:`-protocol entry pointing at B". External deps
|
|
185
|
+
* (registry packages) are not represented — this graph is the input for
|
|
186
|
+
* `topologicalSort` (build order) and `--topological` in `gjsify foreach`.
|
|
187
|
+
*/
|
|
188
|
+
export function buildDependencyGraph(
|
|
189
|
+
workspaces: readonly Workspace[],
|
|
190
|
+
options: BuildGraphOptions = {},
|
|
191
|
+
): DependencyGraph {
|
|
192
|
+
const includeDev = options.includeDev ?? false;
|
|
193
|
+
const includePeer = options.includePeer ?? false;
|
|
194
|
+
const includeOptional = options.includeOptional ?? true;
|
|
195
|
+
const byName = indexByName(workspaces);
|
|
196
|
+
const edges = new Map<string, Set<string>>();
|
|
197
|
+
|
|
198
|
+
for (const ws of workspaces) {
|
|
199
|
+
const deps = new Set<string>();
|
|
200
|
+
const m = ws.manifest;
|
|
201
|
+
for (const block of [
|
|
202
|
+
m.dependencies,
|
|
203
|
+
includeDev ? m.devDependencies : undefined,
|
|
204
|
+
includePeer ? m.peerDependencies : undefined,
|
|
205
|
+
includeOptional ? m.optionalDependencies : undefined,
|
|
206
|
+
]) {
|
|
207
|
+
if (!block) continue;
|
|
208
|
+
for (const [depName, spec] of Object.entries(block)) {
|
|
209
|
+
if (typeof spec !== 'string') continue;
|
|
210
|
+
// Only inter-workspace edges. External deps go via the
|
|
211
|
+
// resolver, not the graph.
|
|
212
|
+
if (!spec.startsWith('workspace:')) continue;
|
|
213
|
+
if (!byName.has(depName)) continue;
|
|
214
|
+
deps.add(depName);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
edges.set(ws.name, deps);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return { edges, byName };
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Kahn's algorithm: returns workspaces in topological build order, so each
|
|
225
|
+
* workspace appears after all of its inter-workspace dependencies. Throws
|
|
226
|
+
* on cycle — yarn's `workspaces foreach --topological` does the same.
|
|
227
|
+
*/
|
|
228
|
+
export function topologicalSort(graph: DependencyGraph): Workspace[] {
|
|
229
|
+
const incoming = new Map<string, number>();
|
|
230
|
+
for (const name of graph.edges.keys()) incoming.set(name, 0);
|
|
231
|
+
for (const deps of graph.edges.values()) {
|
|
232
|
+
for (const dep of deps) {
|
|
233
|
+
// Only count edges where both endpoints are workspaces in the
|
|
234
|
+
// graph (already filtered in `buildDependencyGraph`).
|
|
235
|
+
if (incoming.has(dep)) incoming.set(dep, (incoming.get(dep) ?? 0) + 1);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
// `edges` records "A depends on B". Build orderings need "B before A"
|
|
239
|
+
// — so we work on the REVERSED edges. `incoming` above counts the
|
|
240
|
+
// number of workspaces that depend on a given target (reverse-fanout).
|
|
241
|
+
// A node with 0 reverse-fanout has no dependents → can be emitted last.
|
|
242
|
+
// Easier: invert the dependency direction up front.
|
|
243
|
+
const reverse = new Map<string, Set<string>>();
|
|
244
|
+
const inDegree = new Map<string, number>();
|
|
245
|
+
for (const name of graph.edges.keys()) {
|
|
246
|
+
reverse.set(name, new Set());
|
|
247
|
+
inDegree.set(name, 0);
|
|
248
|
+
}
|
|
249
|
+
for (const [from, deps] of graph.edges) {
|
|
250
|
+
for (const dep of deps) {
|
|
251
|
+
if (!reverse.has(dep)) continue;
|
|
252
|
+
reverse.get(dep)!.add(from);
|
|
253
|
+
inDegree.set(from, (inDegree.get(from) ?? 0) + 1);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const queue: string[] = [];
|
|
258
|
+
for (const [name, deg] of inDegree) {
|
|
259
|
+
if (deg === 0) queue.push(name);
|
|
260
|
+
}
|
|
261
|
+
queue.sort();
|
|
262
|
+
|
|
263
|
+
const out: Workspace[] = [];
|
|
264
|
+
while (queue.length > 0) {
|
|
265
|
+
const name = queue.shift()!;
|
|
266
|
+
const ws = graph.byName.get(name);
|
|
267
|
+
if (ws) out.push(ws);
|
|
268
|
+
const dependents = reverse.get(name);
|
|
269
|
+
if (dependents) {
|
|
270
|
+
const newlyFree: string[] = [];
|
|
271
|
+
for (const d of dependents) {
|
|
272
|
+
const next = (inDegree.get(d) ?? 1) - 1;
|
|
273
|
+
inDegree.set(d, next);
|
|
274
|
+
if (next === 0) newlyFree.push(d);
|
|
275
|
+
}
|
|
276
|
+
newlyFree.sort();
|
|
277
|
+
queue.push(...newlyFree);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
if (out.length !== inDegree.size) {
|
|
282
|
+
const remaining = [...inDegree.entries()].filter(([, d]) => d > 0).map(([n]) => n);
|
|
283
|
+
throw new Error(
|
|
284
|
+
`@gjsify/workspace: dependency cycle detected involving ${remaining.join(', ')}`,
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
return out;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Filter workspaces by glob-pattern include/exclude (mirrors
|
|
292
|
+
* `yarn workspaces foreach --include '@gjsify/example-*' --exclude
|
|
293
|
+
* '@gjsify/example-*-net'` shape). Uses a minimal glob: only `*` is
|
|
294
|
+
* supported (matches any non-`/` segment). That covers every pattern the
|
|
295
|
+
* gjsify monorepo + ts-for-gir actually use.
|
|
296
|
+
*/
|
|
297
|
+
export function filterWorkspaces(
|
|
298
|
+
workspaces: readonly Workspace[],
|
|
299
|
+
options: {
|
|
300
|
+
include?: readonly string[];
|
|
301
|
+
exclude?: readonly string[];
|
|
302
|
+
noPrivate?: boolean;
|
|
303
|
+
},
|
|
304
|
+
): Workspace[] {
|
|
305
|
+
const include = options.include?.map(globToRegex);
|
|
306
|
+
const exclude = options.exclude?.map(globToRegex);
|
|
307
|
+
return workspaces.filter((ws) => {
|
|
308
|
+
if (options.noPrivate && ws.private) return false;
|
|
309
|
+
if (include && include.length > 0 && !include.some((re) => re.test(ws.name))) {
|
|
310
|
+
return false;
|
|
311
|
+
}
|
|
312
|
+
if (exclude && exclude.length > 0 && exclude.some((re) => re.test(ws.name))) {
|
|
313
|
+
return false;
|
|
314
|
+
}
|
|
315
|
+
return true;
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// --- internals -------------------------------------------------------------
|
|
320
|
+
|
|
321
|
+
function extractWorkspacePatterns(manifest: WorkspaceManifest): string[] {
|
|
322
|
+
const ws = manifest.workspaces;
|
|
323
|
+
if (!ws) return [];
|
|
324
|
+
if (Array.isArray(ws)) return ws;
|
|
325
|
+
return ws.packages ?? [];
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
function expandPattern(root: string, pattern: string): string[] {
|
|
329
|
+
// Only the limited form yarn projects use in practice:
|
|
330
|
+
// `<segment>/*` → all immediate children of segment
|
|
331
|
+
// `<segment>` → single literal path
|
|
332
|
+
// `<segment>/*/*` → two levels (`packages/infra/*`)
|
|
333
|
+
// Any deeper nesting is rejected — there's no recursive `**` in our
|
|
334
|
+
// monorepo or ts-for-gir's, so we don't accept it.
|
|
335
|
+
const segments = pattern.split('/').filter(Boolean);
|
|
336
|
+
let current: string[] = [resolve(root)];
|
|
337
|
+
for (const seg of segments) {
|
|
338
|
+
const next: string[] = [];
|
|
339
|
+
for (const dir of current) {
|
|
340
|
+
if (seg === '*') {
|
|
341
|
+
let entries: string[] = [];
|
|
342
|
+
try { entries = readdirSync(dir); } catch { continue; }
|
|
343
|
+
for (const entry of entries) {
|
|
344
|
+
if (entry.startsWith('.')) continue;
|
|
345
|
+
const candidate = join(dir, entry);
|
|
346
|
+
try {
|
|
347
|
+
if (statSync(candidate).isDirectory()) next.push(candidate);
|
|
348
|
+
} catch { /* dead symlink etc. */ }
|
|
349
|
+
}
|
|
350
|
+
} else if (seg.includes('*')) {
|
|
351
|
+
// `pkg-*` style pattern: glob within a single segment.
|
|
352
|
+
const re = globToRegex(seg);
|
|
353
|
+
let entries: string[] = [];
|
|
354
|
+
try { entries = readdirSync(dir); } catch { continue; }
|
|
355
|
+
for (const entry of entries) {
|
|
356
|
+
if (entry.startsWith('.')) continue;
|
|
357
|
+
if (!re.test(entry)) continue;
|
|
358
|
+
const candidate = join(dir, entry);
|
|
359
|
+
try {
|
|
360
|
+
if (statSync(candidate).isDirectory()) next.push(candidate);
|
|
361
|
+
} catch { /* skip */ }
|
|
362
|
+
}
|
|
363
|
+
} else {
|
|
364
|
+
const candidate = join(dir, seg);
|
|
365
|
+
if (existsSync(candidate)) {
|
|
366
|
+
try {
|
|
367
|
+
if (statSync(candidate).isDirectory()) next.push(candidate);
|
|
368
|
+
} catch { /* skip */ }
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
current = next;
|
|
373
|
+
}
|
|
374
|
+
return current;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
function globToRegex(pattern: string): RegExp {
|
|
378
|
+
// Escape regex specials EXCEPT `*`, then map `*` → `[^/]*`.
|
|
379
|
+
const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, '\\$&').replace(/\*/g, '[^/]*');
|
|
380
|
+
return new RegExp(`^${escaped}$`);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
function indexByName(workspaces: readonly Workspace[]): Map<string, Workspace> {
|
|
384
|
+
const out = new Map<string, Workspace>();
|
|
385
|
+
for (const ws of workspaces) out.set(ws.name, ws);
|
|
386
|
+
return out;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// Re-export commonly used path helpers so consumers don't need a separate
|
|
390
|
+
// `node:path` import alongside `@gjsify/workspace`.
|
|
391
|
+
export { join as joinPath, dirname as dirnamePath };
|
package/src/test.mts
ADDED
package/tsconfig.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"module": "ESNext",
|
|
4
|
+
"target": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"experimentalDecorators": true,
|
|
7
|
+
"declaration": true,
|
|
8
|
+
"allowImportingTsExtensions": false,
|
|
9
|
+
"outDir": "lib/esm",
|
|
10
|
+
"rootDir": "src",
|
|
11
|
+
"declarationDir": "lib/types",
|
|
12
|
+
"composite": true,
|
|
13
|
+
"skipLibCheck": true,
|
|
14
|
+
"strict": true,
|
|
15
|
+
"types": ["node"]
|
|
16
|
+
},
|
|
17
|
+
"include": [
|
|
18
|
+
"src/**/*.ts"
|
|
19
|
+
],
|
|
20
|
+
"exclude": [
|
|
21
|
+
"src/test.mts"
|
|
22
|
+
]
|
|
23
|
+
}
|