Page Not Found
We could not find what you were looking for.
Please contact the owner of the site that linked you to the original URL and let them know their link is broken.
diff --git a/404.html b/404.html index 9e678429a3..7c5aee0733 100644 --- a/404.html +++ b/404.html @@ -17,8 +17,8 @@ - - + +
We could not find what you were looking for.
Please contact the owner of the site that linked you to the original URL and let them know their link is broken.
mdk_typescript
",id:"mdk_typescript",level:3},{value:"mdk_python
",id:"mdk_python",level:3},{value:"mdk_rust
",id:"mdk_rust",level:3}];function h(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,s.R)(),...e.components},{Details:o}=n;return o||function(e,n){throw new Error("Expected "+(n?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}("Details",!0),(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.h1,{id:"metagen",children:"Metagen"}),"\n",(0,r.jsx)(n.admonition,{title:"Beta",type:"warning",children:(0,r.jsx)(n.p,{children:"The following feature is not yet stable."})}),"\n",(0,r.jsxs)(n.p,{children:["Metagen is a code-generator suite that contains implementations that help with development on the Metatype platform. Today, this means a set of generators to help with ",(0,r.jsx)(n.a,{href:"/docs/guides/external-functions",children:"custom functions"})," by generating types, serializers and bindings. It's availaible bundled within the ",(0,r.jsx)(n.a,{href:"/docs/reference/meta-cli",children:"meta CLI"})," and the ",(0,r.jsx)(n.a,{href:"/docs/reference/typegraph#sdks",children:"typegraph SDKs"}),"."]}),"\n",(0,r.jsx)(n.h2,{id:"access-through-cli",children:"Access through CLI"}),"\n",(0,r.jsxs)(n.p,{children:["The meta-cli has a dedicated ",(0,r.jsx)(n.code,{children:"gen"})," command for interacting with metagen. We configure the generators through the ",(0,r.jsx)(n.a,{href:"/docs/reference/meta-cli/configuration-file",children:"standard configuration file"})," under the metagen key."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'typegates:\n # bla bla\n\ntypegraphs:\n # bla bla\n\nmetagen:\n targets:\n main:\n # generator to use\n - generator: mdk_rust\n # path to generate to\n path: ./bff/\n # typegraph path to use\n typegraph_path: ./typegraphs/svc-bff.ts\n # we can have multiple generators per target\n - generator: mdk_rust\n path: ./telemetry/\n typegraph_path: ./typegraphs/svc-telemetry.ts\n # generators might have custom keys\n stubbed_runtimes: ["wasm_wire", "deno"]\n # more than one targets avail if you need them\n iter:\n - generator: mdk_typescript\n path: ./ts/\n # name of typegraph to read from typegate\n typegraph: svc_products\n'})}),"\n",(0,r.jsx)(n.p,{children:"This allows us to invoke the targets from the CLI."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"meta cli gen main\n"})}),"\n",(0,r.jsxs)(n.p,{children:["This will resolve the requisite typegraphs, serialize as needed and put the resulting files at the appropriate locations. If no target name is provied, the CLI will look for a target under the key ",(0,r.jsx)(n.code,{children:"main"})," and invoke it instead."]}),"\n",(0,r.jsx)(n.h2,{id:"access-through-sdk",children:"Access through SDK"}),"\n",(0,r.jsx)(n.p,{children:"Metagen is availaible through the SDK for programmatic access needs and can be helpful when writing tests or when relying on the CLI is not an option."}),"\n",(0,r.jsx)(i.A,{python:t(7797),typescript:t(19507),disablePlayground:!0}),"\n",(0,r.jsx)(n.h2,{id:"generators",children:"Generators"}),"\n",(0,r.jsxs)(n.admonition,{title:"Chicken or the egg?",type:"info",children:[(0,r.jsx)(n.p,{children:"As most of the generators are intended for types to be used by custom functions, they'll require that you declare the custom functions in your typegraph first. This begs the question, how does one declare custom functions that depend on artifacts that are yet to be generated? Typegraphs error out when referenced artifacts aren't found, how does it work in this scenario?"}),(0,r.jsxs)(n.p,{children:["To resolve this concern, the SDKs support a serialization mode that skips resolution of artifacts. This mode is activated when serialization is done for codegen purposes. What this means is that, ",(0,r.jsx)(n.strong,{children:"you can declare non-existent files in your typegraph and codegen should work"}),". Some generators are even smart enough to work around your expected files. Of course, if the files aren't present when you're trying to deply to the typegate, it'll raise an error."]})]}),"\n",(0,r.jsx)(n.h3,{id:"mdk_typescript",children:(0,r.jsx)(n.code,{children:"mdk_typescript"})}),"\n",(0,r.jsx)(n.p,{children:"This generator supports:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Typescript types that map to typegraph types"}),"\n",(0,r.jsxs)(n.li,{children:["Stub function types for custom functions implementors that adhere to typegraph functions.","\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["By default, all function types from the ",(0,r.jsx)(n.code,{children:"DenoRuntime"})," get stub types."]}),"\n",(0,r.jsxs)(n.li,{children:["Use ",(0,r.jsx)(n.code,{children:"stubbed_runtimes"})," to select which runtimes get stubs."]}),"\n"]}),"\n"]}),"\n",(0,r.jsx)(n.li,{children:"Types for interacting with the typegate from within custom functions."}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:"The following example showcases the generator."}),"\n",(0,r.jsx)(n.p,{children:"Typegraph:"}),"\n",(0,r.jsx)(i.A,{python:t(14037),typescript:t(14037),disablePlayground:!0}),"\n",(0,r.jsx)(n.p,{children:"Custom function:"}),"\n",(0,r.jsx)(i.A,{typescript:t(13246),disablePlayground:!0}),"\n",(0,r.jsxs)(o,{children:[(0,r.jsx)("summary",{children:(0,r.jsx)(n.p,{children:"Code generation sample."})}),(0,r.jsx)(i.A,{typescript:t(51481),disablePlayground:!0})]}),"\n",(0,r.jsx)(n.p,{children:"It supports the following extra configuration keys."}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Key"}),(0,r.jsx)(n.th,{children:"Type"}),(0,r.jsx)(n.th,{children:"Default"}),(0,r.jsx)(n.th,{children:"Description"})]})}),(0,r.jsx)(n.tbody,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"stubbed_runtimes"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"string[]"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:'["deno"]'})}),(0,r.jsx)(n.td,{children:"Runtimes for which to generate stub types."})]})})]}),"\n",(0,r.jsx)(n.h3,{id:"mdk_python",children:(0,r.jsx)(n.code,{children:"mdk_python"})}),"\n",(0,r.jsx)(n.p,{children:"This generator supports:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Python classes that map to typegraph types"}),"\n",(0,r.jsxs)(n.li,{children:["Decorators for custom functions implementors that require adherance to typegraph function types.","\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["By default, all functions from the ",(0,r.jsx)(n.code,{children:"PythonRuntime"})," get stub types."]}),"\n",(0,r.jsxs)(n.li,{children:["TODO: ",(0,r.jsx)(n.code,{children:"stubbed_runtimes"})," for ",(0,r.jsx)(n.code,{children:"mdk_python"})]}),"\n"]}),"\n"]}),"\n",(0,r.jsx)(n.li,{children:"TODO: types for interacting with the typegate from within custom functions."}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:"If the referenced module for the custom function is not found, the generator will also output stub implementation (in addition to the types) at the given type. It will not replace our code on a second run."}),"\n",(0,r.jsx)(n.p,{children:"The following example showcases the generator."}),"\n",(0,r.jsx)(n.p,{children:"Typegraph:"}),"\n",(0,r.jsx)(i.A,{typescript:t(62292),disablePlayground:!0}),"\n",(0,r.jsx)(n.p,{children:"Custom function:"}),"\n",(0,r.jsx)(i.A,{python:t(28434),disablePlayground:!0}),"\n",(0,r.jsxs)(o,{children:[(0,r.jsx)("summary",{children:(0,r.jsx)(n.p,{children:"Code generation sample."})}),(0,r.jsx)(i.A,{python:t(95696),disablePlayground:!0})]}),"\n",(0,r.jsx)(n.h3,{id:"mdk_rust",children:(0,r.jsx)(n.code,{children:"mdk_rust"})}),"\n",(0,r.jsx)(n.p,{children:"This generator generates types, serializers and bindings needed to implement custom functions in Rust. Rust implementations will need to be compiled to wasm components to be executed on the metatype platform and the generator assumes such usage."}),"\n",(0,r.jsx)(n.p,{children:"To be more specific, it supports:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["Rust types that map to typegraph defined types","\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["Serialization is handled out of sight through ",(0,r.jsx)(n.a,{href:"https://lib.rs/serde_json",children:(0,r.jsx)(n.code,{children:"serde_json"})})]}),"\n"]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["Stub traits for custom functions implementors that adhere to typegraph functions.","\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["By default, all functions from the ",(0,r.jsx)(n.code,{children:"WasmRuntime"})," get stub types."]}),"\n",(0,r.jsxs)(n.li,{children:["The generator assumes the ",(0,r.jsx)(n.code,{children:"wire"})," based wasm interface is being targetted."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"stubbed_runtimes"})," key can be used to configure stub generation from additional runtimes."]}),"\n"]}),"\n"]}),"\n",(0,r.jsx)(n.li,{children:"Types for interacting with the typegate from within custom functions."}),"\n",(0,r.jsxs)(n.li,{children:["Glue code for setting up the wasm component to be run within the ",(0,r.jsx)(n.code,{children:"WasmRuntime"}),"."]}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:"By default the generator will also output a library crate entrypoint and a functional Cargo.toml with all the required dependencies. These additional files wlil not be overwritten on a second run. The generator can also be configured to avoid generating them even if not present."}),"\n",(0,r.jsx)(n.p,{children:"The following example showcases the generator."}),"\n",(0,r.jsx)(n.p,{children:"Typegraph:"}),"\n",(0,r.jsx)(i.A,{python:t(28054),typescript:t(86016),disablePlayground:!0}),"\n",(0,r.jsx)(n.p,{children:"Custom function:"}),"\n",(0,r.jsx)(a.A,{language:"rust",children:t(39028).content}),"\n",(0,r.jsxs)(o,{children:[(0,r.jsx)("summary",{children:"Code generation sample."}),(0,r.jsx)(a.A,{language:"rust",children:t(95985).content})]}),"\n",(0,r.jsx)(n.p,{children:"It supports the following extra configuration keys."}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Key"}),(0,r.jsx)(n.th,{children:"Type"}),(0,r.jsx)(n.th,{children:"Default"}),(0,r.jsx)(n.th,{children:"Description"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"stubbed_runtimes"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"string[]"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:'["wasm_wire"]'})}),(0,r.jsx)(n.td,{children:"Runtimes for which to generate stub types."})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"crate_name"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"string"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"${typegraphName}_mdk"})}),(0,r.jsxs)(n.td,{children:["Name to assign to crate when generating ",(0,r.jsx)(n.code,{children:"Cargo.toml"}),"."]})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"skip_cargo_toml"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"boolean"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"false"})}),(0,r.jsxs)(n.td,{children:["Do not generate ",(0,r.jsx)(n.code,{children:"Cargo.toml"}),"."]})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"skip_lib_rs"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"boolean"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"false"})}),(0,r.jsxs)(n.td,{children:["Do not generate ",(0,r.jsx)(n.code,{children:"lib.rs"}),", the sample entrypoint."]})]})]})]})]})}function m(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(h,{...e})}):h(e)}},14037:e=>{e.exports={content:'@typegraph(\n)\ndef metagen_deno(g: Graph):\n idv3 = t.struct(\n {\n "title": t.string(),\n "artist": t.string(),\n "releaseTime": t.datetime(),\n "mp3Url": t.uri(),\n # explicit type names help when generating code\n }\n ).rename("idv3")\n deno = DenoRuntime()\n\n g.expose(\n Policy.public(),\n remix=deno.import_(\n idv3,\n idv3,\n module="./metagen/ts/remix.ts",\n deps=["./metagen/ts/mdk.ts"],\n name="remix_track",\n ).rename("remix_track"), # explicit names help\n )',path:"../examples/typegraphs/metagen-deno.py"}},62292:e=>{e.exports={content:'await typegraph(\n {\n name: "metagen-py",\n },\n (g) => {\n const idv3 = t\n .struct({\n title: t.string(),\n artist: t.string(),\n releaseTime: t.datetime(),\n mp3Url: t.uri(),\n // explicit type names help when generating code\n })\n .rename("idv3");\n\n const python = new PythonRuntime();\n\n g.expose(\n {\n remix: python\n .import(idv3, idv3, {\n module: "./metagen/py/remix.py",\n deps: ["./metagen/py/remix_types.py"],\n name: "remix_track",\n })\n .rename("remix_track"), // explicit names help\n },\n Policy.public()\n );\n }\n);',path:"../examples/typegraphs/metagen-py.ts"}},28054:e=>{e.exports={content:'@typegraph(\n)\ndef metagen_rs(g: Graph):\n idv3 = t.struct(\n {\n "title": t.string(),\n "artist": t.string(),\n "releaseTime": t.datetime(),\n "mp3Url": t.uri(),\n # explicit type names help when generating code\n }\n ).rename("idv3")\n\n # the wire flavour is availible through a static\n # constructor\n wasm = WasmRuntime.wire("metagen/rust.wasm")\n\n g.expose(\n Policy.public(),\n remix=wasm.handler(\n idv3,\n idv3,\n name="remix_track",\n ).rename("remix_track"), # explicit names help\n )',path:"../examples/typegraphs/metagen-rs.py"}},86016:e=>{e.exports={content:'await typegraph(\n {\n name: "metagen-rs",\n },\n (g) => {\n const idv3 = t\n .struct({\n title: t.string(),\n artist: t.string(),\n releaseTime: t.datetime(),\n mp3Url: t.uri(),\n // explicit type names help when generating code\n })\n .rename("idv3");\n\n // the wire flavour is availible through a static\n // constructor\n const wasm = WasmRuntime.wire("metagen/rust.wasm");\n\n g.expose(\n {\n remix: wasm\n .handler(\n idv3,\n idv3,\n {\n name: "remix_track",\n }\n // the traits will map to the name of the materializer\n // and also the the name of the handler mentioned above\n )\n .rename("remix_track"),\n },\n Policy.public()\n );\n }\n);',path:"../examples/typegraphs/metagen-rs.ts"}},7797:e=>{e.exports={content:'import os\nfrom typegraph.graph.metagen import Metagen\n\n\n@typegraph(\n)\ndef metagen_sdk(g: Graph):\n idv3 = t.struct(\n {\n "title": t.string(),\n "artist": t.string(),\n "releaseTime": t.datetime(),\n "mp3Url": t.uri(),\n }\n ).rename("idv3")\n deno = DenoRuntime()\n\n g.expose(\n Policy.public(),\n remix=deno.import_(\n idv3,\n idv3,\n module="./metagen/ts/remix.ts",\n deps=["./metagen/ts/mdk.ts"],\n name="remix_track",\n ).rename("remix_track"),\n )\n\n\nif __name__ == "__main__" and False:\n metagen = Metagen(\n # the workspace root that our config is relative to\n os.path.dirname(os.path.abspath(__file__)),\n # the rest is pretty similar to the CLI config\n {\n "targets": {\n "main": [\n {\n "generator": "mdk_typescript",\n "typegraph_path": __file__,\n "path": "funcs/",\n },\n ],\n },\n },\n )\n tg = metagen_sdk()\n # dry_run doesn\'t write to disk\n items = metagen.dry_run(tg, "main", None)',path:"../examples/typegraphs/metagen-sdk.py"}},19507:e=>{e.exports={content:'import { Metagen } from "@typegraph/sdk/metagen.ts";\n\n// get typegraph desc here\nconst tg = await typegraph(\n {\n name: "metagen-sdk",\n },\n (g) => {\n const idv3 = t\n .struct({\n title: t.string(),\n artist: t.string(),\n releaseTime: t.datetime(),\n mp3Url: t.uri(),\n })\n .rename("idv3");\n\n const deno = new DenoRuntime();\n\n g.expose(\n {\n remix: deno\n .import(idv3, idv3, {\n module: "./metagen/ts/remix.ts",\n deps: ["./metagen/ts/mdk.ts"],\n name: "remix_track",\n })\n .rename("remix_track"),\n },\n Policy.public()\n );\n }\n);\n\nif (false) {\n const myPath = import.meta.url.replace("file://", "");\n const metagen = new Metagen(\n // the workspace root that our config is relative to\n myPath + "/..",\n // this rest of the config is similmilar to the CLI config\n {\n targets: {\n main: [\n {\n generator: "mdk_typescript",\n typegraph_path: myPath,\n path: "funcs/",\n },\n ],\n },\n }\n );\n // dry_run doesn\'t write to disk\n metagen.dryRun(tg, "main");\n}',path:"../examples/typegraphs/metagen-sdk.ts"}},28434:e=>{e.exports={content:'from .remix_types import typed_remix_track, Idv3\n\n\n# the following decorator makes sure your function\n# adheres to the function types from the typegraph\n@typed_remix_track\ndef remix_track(inp: Idv3) -> Idv3:\n return Idv3(\n title=f"{inp.title} (Remix)",\n artist=f"{inp.artist} + DJ Cloud",\n releaseTime=inp.releaseTime,\n mp3Url="https://mp3.url/remix1",\n )',path:"../examples/typegraphs/metagen/py/remix.py"}},95696:e=>{e.exports={content:'from types import NoneType\nfrom typing import Callable, List, Union, get_origin, ForwardRef, Any\nfrom dataclasses import dataclass, asdict, fields\n\nFORWARD_REFS = {}\n\n\nclass Struct:\n def repr(self):\n return asdict(self)\n\n @staticmethod\n def try_new(dt_class, val: Any):\n # Object\n ftypes = {f.name: f.type for f in fields(dt_class)}\n attrs = {}\n for f in val:\n fval = val[f]\n ftype = ftypes[f]\n serialized = False\n # Union\n if get_origin(ftype) is Union:\n try:\n attrs[f] = Struct.try_union(ftype.__args__, fval)\n serialized = True\n except Exception:\n pass\n # List\n elif get_origin(ftype) is list:\n try:\n attrs[f] = Struct.try_typed_list(ftype.__args__, fval)\n serialized = True\n except Exception:\n pass\n # Any\n if not serialized:\n if isinstance(ftype, str) and ftype in FORWARD_REFS:\n klass = FORWARD_REFS[ftype]\n attrs[f] = Struct.new(klass, fval)\n else:\n attrs[f] = Struct.new(ftype, fval)\n return dt_class(**attrs)\n\n @staticmethod\n def try_typed_list(tpe: Any, items: Any):\n hint = tpe.__args__[0]\n klass = (\n FORWARD_REFS[hint.__forward_arg__] if isinstance(hint, ForwardRef) else hint\n )\n return [Struct.new(klass, v) for v in items]\n\n @staticmethod\n def try_union(variants: List[Any], val: Any):\n errors = []\n for variant in variants:\n try:\n if variant is NoneType:\n if val is None:\n return None\n else:\n continue\n if get_origin(variant) is list:\n if isinstance(val, list):\n return Struct.try_typed_list(variant, val)\n else:\n continue\n klass = FORWARD_REFS[variant.__forward_arg__]\n return Struct.try_new(klass, val)\n except Exception as e:\n errors.append(str(e))\n raise Exception("\\n".join(errors))\n\n @staticmethod\n def new(dt_class: Any, val: Any):\n try:\n return Struct.try_new(dt_class, val)\n except Exception:\n return val\n\n\n@dataclass\nclass Idv3(Struct):\n title: str\n artist: str\n releaseTime: str\n mp3Url: str\n\n\nFORWARD_REFS["Idv3"] = Idv3\n\n\ndef __repr(value: Any):\n if isinstance(value, Struct):\n return value.repr()\n return value\n\n\ndef typed_remix_track(user_fn: Callable[[Idv3], Idv3]):\n def exported_wrapper(raw_inp):\n inp: Idv3 = Struct.new(Idv3, raw_inp)\n out: Idv3 = user_fn(inp)\n if isinstance(out, list):\n return [__repr(v) for v in out]\n return __repr(out)\n\n return exported_wrapper',path:"../examples/typegraphs/metagen/py/remix_types.py"}},39028:e=>{e.exports={content:'mod mdk;\npub use mdk::*;\n\n// the macro sets up all the glue\ninit_mat! {\n // the hook is expected to return a MatBuilder instance\n hook: || {\n // initialize global stuff here if you need it\n MatBuilder::new()\n // register function handlers here\n // each trait will map to the name of the\n // handler found in the typegraph\n .register_handler(stubs::RemixTrack::erased(MyMat))\n }\n}\n\nstruct MyMat;\n\nimpl stubs::RemixTrack for MyMat {\n fn handle(&self, input: types::Idv3, _cx: Ctx) -> anyhow::Resultmdk_typescript
",id:"mdk_typescript",level:3},{value:"mdk_python
",id:"mdk_python",level:3},{value:"mdk_rust
",id:"mdk_rust",level:3}];function h(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,s.R)(),...e.components},{Details:o}=n;return o||function(e,n){throw new Error("Expected "+(n?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}("Details",!0),(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.h1,{id:"metagen",children:"Metagen"}),"\n",(0,r.jsx)(n.admonition,{title:"Beta",type:"warning",children:(0,r.jsx)(n.p,{children:"The following feature is not yet stable."})}),"\n",(0,r.jsxs)(n.p,{children:["Metagen is a code-generator suite that contains implementations that help with development on the Metatype platform. Today, this means a set of generators to help with ",(0,r.jsx)(n.a,{href:"/docs/guides/external-functions",children:"custom functions"})," by generating types, serializers and bindings. It's availaible bundled within the ",(0,r.jsx)(n.a,{href:"/docs/reference/meta-cli",children:"meta CLI"})," and the ",(0,r.jsx)(n.a,{href:"/docs/reference/typegraph#sdks",children:"typegraph SDKs"}),"."]}),"\n",(0,r.jsx)(n.h2,{id:"access-through-cli",children:"Access through CLI"}),"\n",(0,r.jsxs)(n.p,{children:["The meta-cli has a dedicated ",(0,r.jsx)(n.code,{children:"gen"})," command for interacting with metagen. We configure the generators through the ",(0,r.jsx)(n.a,{href:"/docs/reference/meta-cli/configuration-file",children:"standard configuration file"})," under the metagen key."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'typegates:\n # bla bla\n\ntypegraphs:\n # bla bla\n\nmetagen:\n targets:\n main:\n # generator to use\n - generator: mdk_rust\n # path to generate to\n path: ./bff/\n # typegraph path to use\n typegraph_path: ./typegraphs/svc-bff.ts\n # we can have multiple generators per target\n - generator: mdk_rust\n path: ./telemetry/\n typegraph_path: ./typegraphs/svc-telemetry.ts\n # generators might have custom keys\n stubbed_runtimes: ["wasm_wire", "deno"]\n # more than one targets avail if you need them\n iter:\n - generator: mdk_typescript\n path: ./ts/\n # name of typegraph to read from typegate\n typegraph: svc_products\n'})}),"\n",(0,r.jsx)(n.p,{children:"This allows us to invoke the targets from the CLI."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"meta cli gen main\n"})}),"\n",(0,r.jsxs)(n.p,{children:["This will resolve the requisite typegraphs, serialize as needed and put the resulting files at the appropriate locations. If no target name is provied, the CLI will look for a target under the key ",(0,r.jsx)(n.code,{children:"main"})," and invoke it instead."]}),"\n",(0,r.jsx)(n.h2,{id:"access-through-sdk",children:"Access through SDK"}),"\n",(0,r.jsx)(n.p,{children:"Metagen is availaible through the SDK for programmatic access needs and can be helpful when writing tests or when relying on the CLI is not an option."}),"\n",(0,r.jsx)(i.A,{python:t(7797),typescript:t(19507),disablePlayground:!0}),"\n",(0,r.jsx)(n.h2,{id:"generators",children:"Generators"}),"\n",(0,r.jsxs)(n.admonition,{title:"Chicken or the egg?",type:"info",children:[(0,r.jsx)(n.p,{children:"As most of the generators are intended for types to be used by custom functions, they'll require that you declare the custom functions in your typegraph first. This begs the question, how does one declare custom functions that depend on artifacts that are yet to be generated? Typegraphs error out when referenced artifacts aren't found, how does it work in this scenario?"}),(0,r.jsxs)(n.p,{children:["To resolve this concern, the SDKs support a serialization mode that skips resolution of artifacts. This mode is activated when serialization is done for codegen purposes. What this means is that, ",(0,r.jsx)(n.strong,{children:"you can declare non-existent files in your typegraph and codegen should work"}),". Some generators are even smart enough to work around your expected files. Of course, if the files aren't present when you're trying to deply to the typegate, it'll raise an error."]})]}),"\n",(0,r.jsx)(n.h3,{id:"mdk_typescript",children:(0,r.jsx)(n.code,{children:"mdk_typescript"})}),"\n",(0,r.jsx)(n.p,{children:"This generator supports:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Typescript types that map to typegraph types"}),"\n",(0,r.jsxs)(n.li,{children:["Stub function types for custom functions implementors that adhere to typegraph functions.","\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["By default, all function types from the ",(0,r.jsx)(n.code,{children:"DenoRuntime"})," get stub types."]}),"\n",(0,r.jsxs)(n.li,{children:["Use ",(0,r.jsx)(n.code,{children:"stubbed_runtimes"})," to select which runtimes get stubs."]}),"\n"]}),"\n"]}),"\n",(0,r.jsx)(n.li,{children:"Types for interacting with the typegate from within custom functions."}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:"The following example showcases the generator."}),"\n",(0,r.jsx)(n.p,{children:"Typegraph:"}),"\n",(0,r.jsx)(i.A,{python:t(14037),typescript:t(14037),disablePlayground:!0}),"\n",(0,r.jsx)(n.p,{children:"Custom function:"}),"\n",(0,r.jsx)(i.A,{typescript:t(13246),disablePlayground:!0}),"\n",(0,r.jsxs)(o,{children:[(0,r.jsx)("summary",{children:(0,r.jsx)(n.p,{children:"Code generation sample."})}),(0,r.jsx)(i.A,{typescript:t(51481),disablePlayground:!0})]}),"\n",(0,r.jsx)(n.p,{children:"It supports the following extra configuration keys."}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Key"}),(0,r.jsx)(n.th,{children:"Type"}),(0,r.jsx)(n.th,{children:"Default"}),(0,r.jsx)(n.th,{children:"Description"})]})}),(0,r.jsx)(n.tbody,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"stubbed_runtimes"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"string[]"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:'["deno"]'})}),(0,r.jsx)(n.td,{children:"Runtimes for which to generate stub types."})]})})]}),"\n",(0,r.jsx)(n.h3,{id:"mdk_python",children:(0,r.jsx)(n.code,{children:"mdk_python"})}),"\n",(0,r.jsx)(n.p,{children:"This generator supports:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Python classes that map to typegraph types"}),"\n",(0,r.jsxs)(n.li,{children:["Decorators for custom functions implementors that require adherance to typegraph function types.","\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["By default, all functions from the ",(0,r.jsx)(n.code,{children:"PythonRuntime"})," get stub types."]}),"\n",(0,r.jsxs)(n.li,{children:["TODO: ",(0,r.jsx)(n.code,{children:"stubbed_runtimes"})," for ",(0,r.jsx)(n.code,{children:"mdk_python"})]}),"\n"]}),"\n"]}),"\n",(0,r.jsx)(n.li,{children:"TODO: types for interacting with the typegate from within custom functions."}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:"If the referenced module for the custom function is not found, the generator will also output stub implementation (in addition to the types) at the given type. It will not replace our code on a second run."}),"\n",(0,r.jsx)(n.p,{children:"The following example showcases the generator."}),"\n",(0,r.jsx)(n.p,{children:"Typegraph:"}),"\n",(0,r.jsx)(i.A,{typescript:t(62292),disablePlayground:!0}),"\n",(0,r.jsx)(n.p,{children:"Custom function:"}),"\n",(0,r.jsx)(i.A,{python:t(28434),disablePlayground:!0}),"\n",(0,r.jsxs)(o,{children:[(0,r.jsx)("summary",{children:(0,r.jsx)(n.p,{children:"Code generation sample."})}),(0,r.jsx)(i.A,{python:t(95696),disablePlayground:!0})]}),"\n",(0,r.jsx)(n.h3,{id:"mdk_rust",children:(0,r.jsx)(n.code,{children:"mdk_rust"})}),"\n",(0,r.jsx)(n.p,{children:"This generator generates types, serializers and bindings needed to implement custom functions in Rust. Rust implementations will need to be compiled to wasm components to be executed on the metatype platform and the generator assumes such usage."}),"\n",(0,r.jsx)(n.p,{children:"To be more specific, it supports:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["Rust types that map to typegraph defined types","\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["Serialization is handled out of sight through ",(0,r.jsx)(n.a,{href:"https://lib.rs/serde_json",children:(0,r.jsx)(n.code,{children:"serde_json"})})]}),"\n"]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["Stub traits for custom functions implementors that adhere to typegraph functions.","\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["By default, all functions from the ",(0,r.jsx)(n.code,{children:"WasmRuntime"})," get stub types."]}),"\n",(0,r.jsxs)(n.li,{children:["The generator assumes the ",(0,r.jsx)(n.code,{children:"wire"})," based wasm interface is being targetted."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"stubbed_runtimes"})," key can be used to configure stub generation from additional runtimes."]}),"\n"]}),"\n"]}),"\n",(0,r.jsx)(n.li,{children:"Types for interacting with the typegate from within custom functions."}),"\n",(0,r.jsxs)(n.li,{children:["Glue code for setting up the wasm component to be run within the ",(0,r.jsx)(n.code,{children:"WasmRuntime"}),"."]}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:"By default the generator will also output a library crate entrypoint and a functional Cargo.toml with all the required dependencies. These additional files wlil not be overwritten on a second run. The generator can also be configured to avoid generating them even if not present."}),"\n",(0,r.jsx)(n.p,{children:"The following example showcases the generator."}),"\n",(0,r.jsx)(n.p,{children:"Typegraph:"}),"\n",(0,r.jsx)(i.A,{python:t(28054),typescript:t(86016),disablePlayground:!0}),"\n",(0,r.jsx)(n.p,{children:"Custom function:"}),"\n",(0,r.jsx)(a.A,{language:"rust",children:t(39028).content}),"\n",(0,r.jsxs)(o,{children:[(0,r.jsx)("summary",{children:"Code generation sample."}),(0,r.jsx)(a.A,{language:"rust",children:t(95985).content})]}),"\n",(0,r.jsx)(n.p,{children:"It supports the following extra configuration keys."}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Key"}),(0,r.jsx)(n.th,{children:"Type"}),(0,r.jsx)(n.th,{children:"Default"}),(0,r.jsx)(n.th,{children:"Description"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"stubbed_runtimes"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"string[]"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:'["wasm_wire"]'})}),(0,r.jsx)(n.td,{children:"Runtimes for which to generate stub types."})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"crate_name"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"string"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"${typegraphName}_mdk"})}),(0,r.jsxs)(n.td,{children:["Name to assign to crate when generating ",(0,r.jsx)(n.code,{children:"Cargo.toml"}),"."]})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"skip_cargo_toml"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"boolean"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"false"})}),(0,r.jsxs)(n.td,{children:["Do not generate ",(0,r.jsx)(n.code,{children:"Cargo.toml"}),"."]})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"skip_lib_rs"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"boolean"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"false"})}),(0,r.jsxs)(n.td,{children:["Do not generate ",(0,r.jsx)(n.code,{children:"lib.rs"}),", the sample entrypoint."]})]})]})]})]})}function m(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(h,{...e})}):h(e)}},14037:e=>{e.exports={content:'@typegraph(\n)\ndef metagen_deno(g: Graph):\n idv3 = t.struct(\n {\n "title": t.string(),\n "artist": t.string(),\n "releaseTime": t.datetime(),\n "mp3Url": t.uri(),\n # explicit type names help when generating code\n }\n ).rename("idv3")\n deno = DenoRuntime()\n\n g.expose(\n Policy.public(),\n remix=deno.import_(\n idv3,\n idv3,\n module="./metagen/ts/remix.ts",\n deps=["./metagen/ts/mdk.ts"],\n name="remix_track",\n ).rename("remix_track"), # explicit names help\n )',path:"../examples/typegraphs/metagen-deno.py"}},62292:e=>{e.exports={content:'await typegraph(\n {\n name: "metagen-py",\n },\n (g) => {\n const idv3 = t\n .struct({\n title: t.string(),\n artist: t.string(),\n releaseTime: t.datetime(),\n mp3Url: t.uri(),\n // explicit type names help when generating code\n })\n .rename("idv3");\n\n const python = new PythonRuntime();\n\n g.expose(\n {\n remix: python\n .import(idv3, idv3, {\n module: "./metagen/py/remix.py",\n deps: ["./metagen/py/remix_types.py"],\n name: "remix_track",\n })\n .rename("remix_track"), // explicit names help\n },\n Policy.public()\n );\n }\n);',path:"../examples/typegraphs/metagen-py.ts"}},28054:e=>{e.exports={content:'@typegraph(\n)\ndef metagen_rs(g: Graph):\n idv3 = t.struct(\n {\n "title": t.string(),\n "artist": t.string(),\n "releaseTime": t.datetime(),\n "mp3Url": t.uri(),\n # explicit type names help when generating code\n }\n ).rename("idv3")\n\n # the wire flavour is availible through a static\n # constructor\n wasm = WasmRuntime.wire("metagen/rust.wasm")\n\n g.expose(\n Policy.public(),\n remix=wasm.handler(\n idv3,\n idv3,\n name="remix_track",\n ).rename("remix_track"), # explicit names help\n )',path:"../examples/typegraphs/metagen-rs.py"}},86016:e=>{e.exports={content:'await typegraph(\n {\n name: "metagen-rs",\n },\n (g) => {\n const idv3 = t\n .struct({\n title: t.string(),\n artist: t.string(),\n releaseTime: t.datetime(),\n mp3Url: t.uri(),\n // explicit type names help when generating code\n })\n .rename("idv3");\n\n // the wire flavour is availible through a static\n // constructor\n const wasm = WasmRuntime.wire("metagen/rust.wasm");\n\n g.expose(\n {\n remix: wasm\n .handler(\n idv3,\n idv3,\n {\n name: "remix_track",\n }\n // the traits will map to the name of the materializer\n // and also the the name of the handler mentioned above\n )\n .rename("remix_track"),\n },\n Policy.public()\n );\n }\n);',path:"../examples/typegraphs/metagen-rs.ts"}},7797:e=>{e.exports={content:'import os\nfrom typegraph.graph.metagen import Metagen\n\n\n@typegraph(\n)\ndef metagen_sdk(g: Graph):\n idv3 = t.struct(\n {\n "title": t.string(),\n "artist": t.string(),\n "releaseTime": t.datetime(),\n "mp3Url": t.uri(),\n }\n ).rename("idv3")\n deno = DenoRuntime()\n\n g.expose(\n Policy.public(),\n remix=deno.import_(\n idv3,\n idv3,\n module="./metagen/ts/remix.ts",\n deps=["./metagen/ts/mdk.ts"],\n name="remix_track",\n ).rename("remix_track"),\n )\n\n\nif __name__ == "__main__" and False:\n metagen = Metagen(\n # the workspace root that our config is relative to\n os.path.dirname(os.path.abspath(__file__)),\n # the rest is pretty similar to the CLI config\n {\n "targets": {\n "main": [\n {\n "generator": "mdk_typescript",\n "typegraph_path": __file__,\n "path": "funcs/",\n },\n ],\n },\n },\n )\n tg = metagen_sdk()\n # dry_run doesn\'t write to disk\n items = metagen.dry_run(tg, "main", None)',path:"../examples/typegraphs/metagen-sdk.py"}},19507:e=>{e.exports={content:'import { Metagen } from "@typegraph/sdk/metagen.ts";\n\n// get typegraph desc here\nconst tg = await typegraph(\n {\n name: "metagen-sdk",\n },\n (g) => {\n const idv3 = t\n .struct({\n title: t.string(),\n artist: t.string(),\n releaseTime: t.datetime(),\n mp3Url: t.uri(),\n })\n .rename("idv3");\n\n const deno = new DenoRuntime();\n\n g.expose(\n {\n remix: deno\n .import(idv3, idv3, {\n module: "./metagen/ts/remix.ts",\n deps: ["./metagen/ts/mdk.ts"],\n name: "remix_track",\n })\n .rename("remix_track"),\n },\n Policy.public()\n );\n }\n);\n\nif (false) {\n const myPath = import.meta.url.replace("file://", "");\n const metagen = new Metagen(\n // the workspace root that our config is relative to\n myPath + "/..",\n // this rest of the config is similmilar to the CLI config\n {\n targets: {\n main: [\n {\n generator: "mdk_typescript",\n typegraph_path: myPath,\n path: "funcs/",\n },\n ],\n },\n }\n );\n // dry_run doesn\'t write to disk\n metagen.dryRun(tg, "main");\n}',path:"../examples/typegraphs/metagen-sdk.ts"}},28434:e=>{e.exports={content:'from .remix_types import typed_remix_track, Idv3\n\n\n# the following decorator makes sure your function\n# adheres to the function types from the typegraph\n@typed_remix_track\ndef remix_track(inp: Idv3) -> Idv3:\n return Idv3(\n title=f"{inp.title} (Remix)",\n artist=f"{inp.artist} + DJ Cloud",\n releaseTime=inp.releaseTime,\n mp3Url="https://mp3.url/remix1",\n )',path:"../examples/typegraphs/metagen/py/remix.py"}},95696:e=>{e.exports={content:'from types import NoneType\nfrom typing import Callable, List, Union, get_origin, ForwardRef, Any\nfrom dataclasses import dataclass, asdict, fields\n\nFORWARD_REFS = {}\n\n\nclass Struct:\n def repr(self):\n return asdict(self)\n\n @staticmethod\n def try_new(dt_class, val: Any):\n # Object\n ftypes = {f.name: f.type for f in fields(dt_class)}\n attrs = {}\n for f in val:\n fval = val[f]\n ftype = ftypes[f]\n serialized = False\n # Union\n if get_origin(ftype) is Union:\n try:\n attrs[f] = Struct.try_union(ftype.__args__, fval)\n serialized = True\n except Exception:\n pass\n # List\n elif get_origin(ftype) is list:\n try:\n attrs[f] = Struct.try_typed_list(ftype.__args__, fval)\n serialized = True\n except Exception:\n pass\n # Any\n if not serialized:\n if isinstance(ftype, str) and ftype in FORWARD_REFS:\n klass = FORWARD_REFS[ftype]\n attrs[f] = Struct.new(klass, fval)\n else:\n attrs[f] = Struct.new(ftype, fval)\n return dt_class(**attrs)\n\n @staticmethod\n def try_typed_list(tpe: Any, items: Any):\n hint = tpe.__args__[0]\n klass = (\n FORWARD_REFS[hint.__forward_arg__] if isinstance(hint, ForwardRef) else hint\n )\n return [Struct.new(klass, v) for v in items]\n\n @staticmethod\n def try_union(variants: List[Any], val: Any):\n errors = []\n for variant in variants:\n try:\n if variant is NoneType:\n if val is None:\n return None\n else:\n continue\n if get_origin(variant) is list:\n if isinstance(val, list):\n return Struct.try_typed_list(variant, val)\n else:\n continue\n klass = FORWARD_REFS[variant.__forward_arg__]\n return Struct.try_new(klass, val)\n except Exception as e:\n errors.append(str(e))\n raise Exception("\\n".join(errors))\n\n @staticmethod\n def new(dt_class: Any, val: Any):\n try:\n return Struct.try_new(dt_class, val)\n except Exception:\n return val\n\n\n@dataclass\nclass Idv3(Struct):\n title: str\n artist: str\n releaseTime: str\n mp3Url: str\n\n\nFORWARD_REFS["Idv3"] = Idv3\n\n\ndef __repr(value: Any):\n if isinstance(value, Struct):\n return value.repr()\n return value\n\n\ndef typed_remix_track(user_fn: Callable[[Idv3], Idv3]):\n def exported_wrapper(raw_inp):\n inp: Idv3 = Struct.new(Idv3, raw_inp)\n out: Idv3 = user_fn(inp)\n if isinstance(out, list):\n return [__repr(v) for v in out]\n return __repr(out)\n\n return exported_wrapper',path:"../examples/typegraphs/metagen/py/remix_types.py"}},39028:e=>{e.exports={content:'mod mdk;\npub use mdk::*;\n\n// the macro sets up all the glue\ninit_mat! {\n // the hook is expected to return a MatBuilder instance\n hook: || {\n // initialize global stuff here if you need it\n MatBuilder::new()\n // register function handlers here\n // each trait will map to the name of the\n // handler found in the typegraph\n .register_handler(stubs::RemixTrack::erased(MyMat))\n }\n}\n\nstruct MyMat;\n\nimpl stubs::RemixTrack for MyMat {\n fn handle(&self, input: types::Idv3, _cx: Ctx) -> anyhow::ResultYour Docusaurus site did not load properly.
\nA very common reason is a wrong site baseUrl configuration.
\nCurrent configured baseUrl = ${e} ${"/"===e?" (default value)":""}
\nWe suggest trying baseUrl =
\n.comment
can become .namespace--comment
) or replace them with your defined ones (like .editor__comment
). You can even add new classes.",owner:"dvkndn",noCSS:!0},"file-highlight":{title:"File Highlight",description:"Fetch external files and highlight them with Prism. Used on the Prism website itself.",noCSS:!0},"show-language":{title:"Show Language",description:"Display the highlighted language in code blocks (inline code does not show the label).",owner:"nauzilus",noCSS:!0,require:"toolbar"},"jsonp-highlight":{title:"JSONP Highlight",description:"Fetch content with JSONP and highlight some interesting content (e.g. GitHub/Gists or Bitbucket API).",noCSS:!0,owner:"nauzilus"},"highlight-keywords":{title:"Highlight Keywords",description:"Adds special CSS classes for each keyword for fine-grained highlighting.",owner:"vkbansal",noCSS:!0},"remove-initial-line-feed":{title:"Remove initial line feed",description:"Removes the initial line feed in code blocks.",owner:"Golmote",noCSS:!0},"inline-color":{title:"Inline color",description:"Adds a small inline preview for colors in style sheets.",require:"css-extras",owner:"RunDevelopment"},previewers:{title:"Previewers",description:"Previewers for angles, colors, gradients, easing and time.",require:"css-extras",owner:"Golmote"},autoloader:{title:"Autoloader",description:"Automatically loads the needed languages to highlight the code blocks.",owner:"Golmote",noCSS:!0},"keep-markup":{title:"Keep Markup",description:"Prevents custom markup from being dropped out during highlighting.",owner:"Golmote",optional:"normalize-whitespace",noCSS:!0},"command-line":{title:"Command Line",description:"Display a command line with a prompt and, optionally, the output/response from the commands.",owner:"chriswells0"},"unescaped-markup":{title:"Unescaped Markup",description:"Write markup without having to escape anything."},"normalize-whitespace":{title:"Normalize Whitespace",description:"Supports multiple operations to normalize whitespace in code blocks.",owner:"zeitgeist87",optional:"unescaped-markup",noCSS:!0},"data-uri-highlight":{title:"Data-URI Highlight",description:"Highlights data-URI contents.",owner:"Golmote",noCSS:!0},toolbar:{title:"Toolbar",description:"Attach a toolbar for plugins to easily register buttons on the top of a code block.",owner:"mAAdhaTTah"},"copy-to-clipboard":{title:"Copy to Clipboard Button",description:"Add a button that copies the code block to the clipboard when clicked.",owner:"mAAdhaTTah",require:"toolbar",noCSS:!0},"download-button":{title:"Download Button",description:"A button in the toolbar of a code block adding a convenient way to download a code file.",owner:"Golmote",require:"toolbar",noCSS:!0},"match-braces":{title:"Match braces",description:"Highlights matching braces.",owner:"RunDevelopment"},"diff-highlight":{title:"Diff Highlight",description:"Highlights the code inside diff blocks.",owner:"RunDevelopment",require:"diff"},"filter-highlight-all":{title:"Filter highlightAll",description:"Filters the elements the highlightAll
and highlightAllUnder
methods actually highlight.",owner:"RunDevelopment",noCSS:!0},treeview:{title:"Treeview",description:"A language with special styles to highlight file system tree structures.",owner:"Golmote"}}})},46532:(e,t,n)=>{const r=n(39227),o=n(29670),a=new Set;function i(e){void 0===e?e=Object.keys(r.languages).filter((e=>"meta"!=e)):Array.isArray(e)||(e=[e]);const t=[...a,...Object.keys(Prism.languages)];o(r,e,t).load((e=>{if(!(e in r.languages))return void(i.silent||console.warn("Language does not exist: "+e));const t="./prism-"+e;delete n.c[n(57507).resolve(t)],delete Prism.languages[e],n(57507)(t),a.add(e)}))}i.silent=!1,e.exports=i},1274:()=>{!function(e){function t(e,t){return"___"+e.toUpperCase()+t+"___"}Object.defineProperties(e.languages["markup-templating"]={},{buildPlaceholders:{value:function(n,r,o,a){if(n.language===r){var i=n.tokenStack=[];n.code=n.code.replace(o,(function(e){if("function"==typeof a&&!a(e))return e;for(var o,s=i.length;-1!==n.code.indexOf(o=t(r,s));)++s;return i[s]=e,o})),n.grammar=e.languages.markup}}},tokenizePlaceholders:{value:function(n,r){if(n.language===r&&n.tokenStack){n.grammar=e.languages[r];var o=0,a=Object.keys(n.tokenStack);!function i(s){for(var l=0;l