PageSourceSearch

https://glean.software/assets/js/a09c2993.bab0217e.js

js glean.software collected 2026-10-02 04:31:28 UTC 16,728 bytes, 1 lines download raw bytes

1"use strict";(globalThis.webpackChunkwebsite=globalThis.webpackChunkwebsite||[]).push([[5899],{71920(e,n,t){t.r(n),t.d(n,{assets:()=>d,contentTitle:()=>l,default:()=>h,frontMatter:()=>c,metadata:()=>r,toc:()=>u});const r=JSON.parse('{"id":"introduction","title":"Introduction","description":"This is the Glean documentation. It describes all aspects of the","source":"@site/docs/introduction.md","sourceDirName":".","slug":"/introduction","permalink":"/docs/introduction","draft":false,"unlisted":false,"editUrl":"https://github.com/facebookincubator/Glean/tree/main/glean/website/docs/introduction.md","tags":[],"version":"current","frontMatter":{"id":"introduction","title":"Introduction","sidebar_label":"Introduction"},"sidebar":"someSidebar","next":{"title":"Building Glean","permalink":"/docs/building"}}');var o=t(74848),i=t(28453),s=t(14423),a=t(67555);const c={id:"introduction",title:"Introduction",sidebar_label:"Introduction"},l=void 0,d={},u=[{value:"Overview",id:"overview",level:2},{value:"Components",id:"components",level:2}];function f(e){const n={a:"a",em:"em",h2:"h2",li:"li",ol:"ol",p:"p",section:"section",strong:"strong",sup:"sup",ul:"ul",...(0,i.R)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsxs)(s.FbInternalOnly,{children:[(0,o.jsx)(n.p,{children:"This is the Glean documentation. It describes all aspects of the\nsystem, including how to write queries and schemas, and how\nto use the included command-line tools. Use the navigation on the left\nto find all the sections."}),(0,o.jsxs)(n.p,{children:["If you found yourself here by mistake, go back to the\nmain ",(0,o.jsx)(n.a,{href:"https://www.internalfb.com/wiki/Glean/",children:"Glean Wiki"}),"."]})]}),"\n",(0,o.jsxs)(n.p,{children:["Just want to get started and read the docs later? Jump to ",(0,o.jsx)(n.a,{href:"/docs/building",children:"Building\nGlean"}),"."]}),"\n",(0,o.jsx)(n.h2,{id:"overview",children:"Overview"}),"\n",(0,o.jsx)(n.p,{children:"Glean is a system for working with facts about source code. It is\ndesigned for collecting and storing detailed information about code\nstructure, and providing access to the data to power tools and\nexperiences from online IDE features to offline code analysis."}),"\n",(0,o.jsx)(n.p,{children:"For example, Glean can return results for queries that your IDE might\nneed to perform, such as:"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:(0,o.jsx)(n.em,{children:"Where is the definition of this method?"})}),"\n",(0,o.jsx)(n.li,{children:(0,o.jsx)(n.em,{children:"Where are all the callers of this function?"})}),"\n",(0,o.jsx)(n.li,{children:(0,o.jsx)(n.em,{children:"Who inherits from this class?"})}),"\n",(0,o.jsx)(n.li,{children:(0,o.jsx)(n.em,{children:"What are all the declarations in this file?"})}),"\n"]}),"\n",(0,o.jsx)(n.p,{children:"Moreover, Glean can return results for these kinds of queries\naccurately and efficiently on a large-scale codebase."}),"\n",(0,o.jsx)(n.p,{children:"But Glean isn't limited to storing particular kinds of data, or\nanswering particular queries. Glean comes with indexers and schemas\nfor some languages which support queries like the examples above, but\nyou can also define your own schemas and store whatever data you like,\nperhaps augmenting the data that existing indexers collect.  So, for\nexample, you could store test coverage data or profiling data."}),"\n",(0,o.jsx)(n.p,{children:"Glean's powerful query language means that you can build tools around\ncomplex queries of the underlying data. For example, you could search\nfor dead code, write code linters, API migration tools or refactoring\ntools, all by using Glean queries instead of a compiler API to inspect\nthe code structure."}),"\n",(0,o.jsx)(n.h2,{id:"components",children:"Components"}),"\n",(0,o.jsx)(n.p,{children:"Glean consists of the following:"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:["\n",(0,o.jsxs)(n.p,{children:["An ",(0,o.jsx)(n.strong,{children:"efficient storage backend"})," built on\n",(0,o.jsx)(n.a,{href:"https://rocksdb.org/",children:"RocksDB"}),", for storing facts. Facts are\nimmutable terms described by user-defined schemas, and form a\n
1DAG. Facts are automatically de-duplicated by the storage\nbackend. Think of it as being able to store and query the AST of\nyour code, efficiently and with full type-safety",(0,o.jsx)(n.sup,{children:(0,o.jsx)(n.a,{href:"#user-content-fn-1",id:"user-content-fnref-1","data-footnote-ref":!0,"aria-describedby":"footnote-label",children:"1"})}),"."]}),"\n"]}),"\n",(0,o.jsxs)(n.li,{children:["\n",(0,o.jsxs)(n.p,{children:["A query engine implementing our ",(0,o.jsx)(n.strong,{children:(0,o.jsx)(n.a,{href:"/docs/angle/intro",children:"declarative query language\nAngle"})}),".  Angle is a logic language with similarities\nto Datalog, but with extensions that make it suitable for building\ncomplex queries over Glean data",(0,o.jsx)(n.sup,{children:(0,o.jsx)(n.a,{href:"#user-content-fn-2",id:"user-content-fnref-2","data-footnote-ref":!0,"aria-describedby":"footnote-label",children:"2"})}),".  Like in Datalog, Glean can\nderive new facts automatically by ",(0,o.jsx)(n.a,{href:"/docs/derived",children:"defining rules"})," using\nAngle."]}),"\n"]}),"\n",(0,o.jsxs)(n.li,{children:["\n",(0,o.jsxs)(n.p,{children:["A ",(0,o.jsx)(n.strong,{children:(0,o.jsx)(n.a,{href:"/docs/server",children:"server"})})," that manages multiple databases on disk, and\nserves requests from clients to create, write, and query\ndatabases. The server currently uses Thrift, but there's no reason\nthere couldn't also be servers exposing other protocols in the\nfuture.  The server is designed to be deployed at scale, serving\nreplicated databases to large numbers of clients."]}),"\n"]}),"\n",(0,o.jsxs)(n.li,{children:["\n",(0,o.jsxs)(n.p,{children:["An ",(0,o.jsx)(n.strong,{children:(0,o.jsx)(n.a,{href:"/docs/shell",children:"interactive shell"})})," where you can type queries and explore\nthe data."]}),"\n"]}),"\n",(0,o.jsxs)(n.li,{children:["\n",(0,o.jsxs)(n.p,{children:["A ",(0,o.jsx)(n.strong,{children:(0,o.jsx)(n.a,{href:"/docs/cli",children:"command-line tool"})})," for creating, writing, and querying\ndatabases, either directly or by connecting to the server."]}),"\n"]}),"\n",(0,o.jsxs)(n.li,{children:["\n",(0,o.jsxs)(n.p,{children:["Several ",(0,o.jsx)(n.strong,{children:(0,o.jsx)(a.Lw,{file:"glean/schema/source",children:"example schemas"})})," for common programming languages, and\n",(0,o.jsx)(n.strong,{children:(0,o.jsx)(n.a,{href:"/docs/indexer/intro",children:"indexers"})})," for some of those.  Note that Glean\ndoesn't force all the data into a single schema; there can be\narbitrary amounts of language-specific detail in the schema for each\nlanguage. Language-neutral abstractions can be built by ",(0,o.jsx)(a.Lw,{file:"glean/schema/source/codemarkup.angle",children:"deriving facts using Angle"}),"."]}),"\n"]}),"\n",(0,o.jsxs)(n.li,{children:["\n",(0,o.jsxs)(n.p,{children:[(0,o.jsx)(n.strong,{children:(0,o.jsx)(a.Lw,{file:"glean/glass",children:"Glass"})}),",\na language-agnostic symbol server. Glass is a server layer on top of\nGlean that exposes an API for performing common language-independent\nqueries over Glean data, such as listing the symbols in a source\nfile. Glass can be used as the basis for language tools; in fact\nGlass is used to power our Glean-based LSP server."]}),"\n"]}),"\n",(0,o.jsxs)(n.li,{children:["\n",(0,o.jsxs)(n.p,{children:["A ",(0,o.jsx)(n.strong,{children:(0,o.jsx)(a.Lw,{file:"glean/lsp",children:"generic LSP\nserver"})}),", built using Glean and Glass. This can be\nused to browse a large codebase in ",(0,o.jsx)(n.a,{href:"https://code.visualstudio.com/",children:"VS\nCode"}),(0,o.jsx)(n.sup,{children:(0,o.jsx)(n.a,{href:"#user-content-fn-3",id:"user-content-fnref-3","data-footnote-ref":!0,"aria-describedby":"footnote-label",children:"3"})}),": index the code using\nGlean, and connect VS Code to the LSP server to provide common\ncode-navigation features such as go-to-definition, find-references,\nand symbol search."]}),"\n"]}),"\n"]}),"\n","\n",(0,o.jsxs)(n.section,{"data-footnotes":!0,className:"footnotes",children:[(0,o.jsx)(n.h2,{className:"sr-only",id:"footnote-label",children:"Footnotes"}),"\n",(0,o.jsxs)(n.ol,{children:["\n",(0,o.jsxs)(n.li,{id:"user-content-fn-1",children:["\n",(0,o.jsxs)(n.p,{children:["while we could in principle store the full AST, for efficiency\nreasons we typically store only the parts we need for the clients we\nwant to supp
1ort. Usually that means things like the locations of\ndefinitions and cross-references, but not expressions. ",(0,o.jsx)(n.a,{href:"#user-content-fnref-1","data-footnote-backref":"","aria-label":"Back to reference 1",className:"data-footnote-backref",children:"\u21a9"})]}),"\n"]}),"\n",(0,o.jsxs)(n.li,{id:"user-content-fn-2",children:["\n",(0,o.jsxs)(n.p,{children:["If you're familiar with Datalog, it's worth noting that\ncurrently Angle is limited to non-recursive queries only. ",(0,o.jsx)(n.a,{href:"#user-content-fnref-2","data-footnote-backref":"","aria-label":"Back to reference 2",className:"data-footnote-backref",children:"\u21a9"})]}),"\n"]}),"\n",(0,o.jsxs)(n.li,{id:"user-content-fn-3",children:["\n",(0,o.jsxs)(n.p,{children:["Or any IDE that supports LSP. ",(0,o.jsx)(n.a,{href:"#user-content-fnref-3","data-footnote-backref":"","aria-label":"Back to reference 3",className:"data-footnote-backref",children:"\u21a9"})]}),"\n"]}),"\n"]}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,i.R)(),...e.components};return n?(0,o.jsx)(n,{...e,children:(0,o.jsx)(f,{...e})}):f(e)}},67555(e,n,t){t.d(n,{D4:()=>s,Lw:()=>a,gD:()=>c});t(96540);var r=t(14423),o=t(74848);let i;function s(e){return(0,o.jsx)("a",{href:i+e.file,children:e.file})}function a(e){return(0,o.jsx)("a",{href:i+e.file,children:e.children})}i=(0,r.isInternal)()?"https://www.internalfb.com/code/fbsource/fbcode/":"https://github.com/facebookincubator/Glean/tree/master/";const c=({children:e,internal:n,external:t})=>(0,r.fbContent)({internal:(0,o.jsx)("code",{children:n}),external:(0,o.jsx)("code",{children:t})})},80510(e,n,t){var r=this&&this.__awaiter||function(e,n,t,r){return new(t||(t=Promise))(function(o,i){function s(e){try{c(r.next(e))}catch(n){i(n)}}function a(e){try{c(r.throw(e))}catch(n){i(n)}}function c(e){var n;e.done?o(e.value):(n=e.value,n instanceof t?n:new t(function(e){e(n)})).then(s,a)}c((r=r.apply(e,n||[])).next())})};Object.defineProperty(n,"__esModule",{value:!0}),n.getSpecInfo=void 0;const o=t(88266);n.getSpecInfo=function(e){return r(this,void 0,void 0,function*(){return yield o.call({module:"bloks",api:"getSpecInfo",args:{styleId:e}})})}},88266(e,n){var t=this&&this.__awaiter||function(e,n,t,r){return new(t||(t=Promise))(function(o,i){function s(e){try{c(r.next(e))}catch(n){i(n)}}function a(e){try{c(r.throw(e))}catch(n){i(n)}}function c(e){var n;e.done?o(e.value):(n=e.value,n instanceof t?n:new t(function(e){e(n)})).then(s,a)}c((r=r.apply(e,n||[])).next())})};Object.defineProperty(n,"__esModule",{value:!0}),n.call=void 0;let r=!1,o=0;const i={};n.call=function(e){return t(this,void 0,void 0,function*(){if("staticdocs.thefacebook.com"!==window.location.hostname&&"localhost"!==window.location.hostname)return Promise.reject(new Error("Not running on static docs"));r||(r=!0,window.addEventListener("message",e=>{if("static-docs-bridge-response"!==e.data.event)return;const n=e.data.id;n in i||console.error(`Recieved response for id: ${n} with no matching receiver`),"response"in e.data?i[n].resolve(e.data.response):i[n].reject(new Error(e.data.error)),delete i[n]}));const n=o++,t=new Promise((e,t)=>{i[n]={resolve:e,reject:t}}),s={event:"static-docs-bridge-call",id:n,module:e.module,api:e.api,args:e.args},a="localhost"===window.location.hostname?"*":"https://www.internalfb.com";return window.parent.postMessage(s,a),t})}},70680(e,n,t){var r=this&&this.__awaiter||function(e,n,t,r){return new(t||(t=Promise))(function(o,i){function s(e){try{c(r.next(e))}catch(n){i(n)}}function a(e){try{c(r.throw(e))}catch(n){i(n)}}function c(e){var n;e.done?o(e.value):(n=e.value,n instanceof t?n:new t(function(e){e(n)})).then(s,a)}c((r=r.apply(e,n||[])).next())})};Object.defineProperty(n,"__esModule",{value:!0}),n.reportFeatureUsage=n.reportContentCopied=void 0;const o=t(88266);n.reportContentCopied=function(e){return r(this,void 0,void 0,function*(){const{textContent:n}=e;try{yield o.call({module:"feedback",api:"reportContentCopied",args:{textContent:n}})}catch(t){}})},n.reportFeatureUsage=function(e){return r(this,void 0,void 0,function*(){const{featureName:n,id:t}=e;console.log("used feature");try{yield o.call({module:"feedback",api:"reportFeatureUsage",args:{featureName:n,id:t}})}catch(r){}})}},14423(e,n,t){var r=this&&this.__createBinding||(Object.create?function(e,n,t,r){void 0===r&&(r=t),Object.defineProperty(e,r,{enumerable:!0,get:function(){return n[t]}})}:function(e,n,t,r){void 0===r&&(r=t),e[r]=n[t]}),o=this&&this.__setModuleDefault||(Object.create?function(e,n){Object.defineProperty(e,"default",{enumerable:!0,value:n})}:function(e,n){e.default=n}
1),i=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var n={};if(null!=e)for(var t in e)"default"!==t&&Object.prototype.hasOwnProperty.call(e,t)&&r(n,e,t);return o(n,e),n};Object.defineProperty(n,"__esModule",{value:!0}),n.OssOnly=n.FbInternalOnly=n.getEphemeralDiffNumber=n.hasEphemeralDiffNumber=n.isInternal=n.validateFbContentArgs=n.fbInternalOnly=n.fbContent=n.inpageeditor=n.feedback=n.uidocs=n.bloks=void 0,n.bloks=i(t(80510)),n.uidocs=i(t(3730)),n.feedback=i(t(70680)),n.inpageeditor=i(t(45458));const s=["internal","external"];function a(e){return l(e),d()?"internal"in e?c(e.internal):[]:"external"in e?c(e.external):[]}function c(e){return"function"==typeof e?e():e}function l(e){if("object"!=typeof e)throw new Error(`fbContent() args must be an object containing keys: ${s}. Instead got ${e}`);if(!Object.keys(e).find(e=>s.find(n=>n===e)))throw new Error(`No valid args found in ${JSON.stringify(e)}. Accepted keys: ${s}`);const n=Object.keys(e).filter(e=>!s.find(n=>n===e));if(n.length>0)throw new Error(`Unexpected keys ${n} found in fbContent() args. Accepted keys: ${s}`)}function d(){try{return Boolean(!1)}catch(e){return console.log("process.env.FB_INTERNAL couldn't be read, maybe you forgot to add the required webpack EnvironmentPlugin config?",e),!1}}function u(){try{return null}catch(e){return console.log("process.env.PHABRICATOR_DIFF_NUMBER couldn't be read, maybe you forgot to add the required webpack EnvironmentPlugin config?",e),null}}n.fbContent=a,n.fbInternalOnly=function(e){return a({internal:e})},n.validateFbContentArgs=l,n.isInternal=d,n.hasEphemeralDiffNumber=function(){return Boolean(u())},n.getEphemeralDiffNumber=u,n.FbInternalOnly=function(e){return d()?e.children:null},n.OssOnly=function(e){return d()?null:e.children}},45458(e,n,t){var r=this&&this.__awaiter||function(e,n,t,r){return new(t||(t=Promise))(function(o,i){function s(e){try{c(r.next(e))}catch(n){i(n)}}function a(e){try{c(r.throw(e))}catch(n){i(n)}}function c(e){var n;e.done?o(e.value):(n=e.value,n instanceof t?n:new t(function(e){e(n)})).then(s,a)}c((r=r.apply(e,n||[])).next())})};Object.defineProperty(n,"__esModule",{value:!0}),n.submitDiff=void 0;const o=t(88266);n.submitDiff=function(e){return r(this,void 0,void 0,function*(){const{file_path:n,new_content:t,project_name:r,diff_number:i}=e;try{return yield o.call({module:"inpageeditor",api:"createPhabricatorDiffApi",args:{file_path:n,new_content:t,project_name:r,diff_number:i}})}catch(s){throw new Error(`Error occurred while trying to submit diff. Stack trace: ${s}`)}})}},3730(e,n,t){var r=this&&this.__awaiter||function(e,n,t,r){return new(t||(t=Promise))(function(o,i){function s(e){try{c(r.next(e))}catch(n){i(n)}}function a(e){try{c(r.throw(e))}catch(n){i(n)}}function c(e){var n;e.done?o(e.value):(n=e.value,n instanceof t?n:new t(function(e){e(n)})).then(s,a)}c((r=r.apply(e,n||[])).next())})};Object.defineProperty(n,"__esModule",{value:!0}),n.getApi=n.docsets=void 0;const o=t(88266);n.docsets={BLOKS_CORE:"887372105406659"},n.getApi=function(e){return r(this,void 0,void 0,function*(){const{name:n,framework:t,docset:r}=e;return yield o.call({module:"uidocs",api:"getApi",args:{name:n,framework:t,docset:r}})})}},28453(e,n,t){t.d(n,{R:()=>s,x:()=>a});var r=t(96540);const o={},i=r.createContext(o);function s(e){const n=r.useContext(i);return r.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:s(e.components),r.createElement(i.Provider,{value:n},e.children)}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.