This is an automated email from the ASF dual-hosted git repository.

kaxil pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/main by this push:
     new 518f8d2e7be Lazy-load the Code tab grammar from the Dag's stored 
language (#74643)
518f8d2e7be is described below

commit 518f8d2e7be6bc448b8e641aef4e8eff30d2b560
Author: Pierre Jeambrun <[email protected]>
AuthorDate: Tue Oct 13 22:56:28 2026 +0200

    Lazy-load the Code tab grammar from the Dag's stored language (#74643)
    
    Dag importers are pluggable, so core cannot list every language an importer 
may
    store in dag_code.language. Registering monaco's lazy grammar loaders lets 
the
    Code tab highlight any language monaco ships, fetching a grammar only when a
    Dag source first uses it.
---
 .../MonacoEditor/configureMonaco.test.ts           |  35 +++---
 .../src/components/MonacoEditor/configureMonaco.ts | 128 ++++++---------------
 airflow-core/src/airflow/ui/src/vite-env.d.ts      |  30 +----
 3 files changed, 54 insertions(+), 139 deletions(-)

diff --git 
a/airflow-core/src/airflow/ui/src/components/MonacoEditor/configureMonaco.test.ts
 
b/airflow-core/src/airflow/ui/src/components/MonacoEditor/configureMonaco.test.ts
index a9816858ae0..382a45a893a 100644
--- 
a/airflow-core/src/airflow/ui/src/components/MonacoEditor/configureMonaco.test.ts
+++ 
b/airflow-core/src/airflow/ui/src/components/MonacoEditor/configureMonaco.test.ts
@@ -18,28 +18,33 @@
  */
 import { describe, expect, it } from "vitest";
 
+import { configureMonaco } from "./configureMonaco";
+
 // A Monaco upgrade that moved a module or dropped an export
 // would slip through CI and only surface as silently-unhighlighted code in 
production.
 // Importing the modules here fails the build loudly instead: a missing module 
breaks resolution,
 // a dropped export fails the assertion.
-const grammars = [
-  { id: "go", load: () => import("monaco-editor/languages/definitions/go/go") 
},
-  { id: "java", load: () => 
import("monaco-editor/languages/definitions/java/java") },
-  { id: "python", load: () => 
import("monaco-editor/languages/definitions/python/python") },
-  { id: "typescript", load: () => 
import("monaco-editor/languages/definitions/typescript/typescript") },
-  { id: "yaml", load: () => 
import("monaco-editor/languages/definitions/yaml/yaml") },
-] as const;
-
 describe("Monaco Dag-code grammars", () => {
-  it.each(grammars)(
-    "$id exposes the { conf, language } Monarch shape configureMonaco 
registers",
-    async ({ load }) => {
-      const { conf, language } = await load();
+  // Any language id an importer stores must be highlightable, not only the 
ones core ships.
+  it.each(["go", "java", "python", "rust", "typescript", "yaml"])(
+    "registers %s for lazy loading",
+    async (languageId) => {
+      await configureMonaco();
+      const { languages } = await import("monaco-editor/editor");
 
-      expect(conf).toBeDefined();
-      expect(language).toBeDefined();
-      expect(language.tokenizer).toBeDefined();
+      expect(languages.getLanguages().map(({ id }) => 
id)).toContain(languageId);
     },
     30_000,
   );
+
+  it("tokenizes Python with the patched f-string grammar", async () => {
+    await configureMonaco();
+    const { editor } = await import("monaco-editor/editor");
+
+    // Resolves the lazy tokenizer, which `tokenize` alone does not trigger.
+    await editor.colorize("", "python", {});
+    const [, escapedBracesLine] = editor.tokenize('x = f"""\n{{a}}\n"""', 
"python");
+
+    expect(escapedBracesLine).toEqual([{ language: "python", offset: 0, type: 
"string.python" }]);
+  }, 30_000);
 });
diff --git 
a/airflow-core/src/airflow/ui/src/components/MonacoEditor/configureMonaco.ts 
b/airflow-core/src/airflow/ui/src/components/MonacoEditor/configureMonaco.ts
index bfc28915c69..7929499b065 100644
--- a/airflow-core/src/airflow/ui/src/components/MonacoEditor/configureMonaco.ts
+++ b/airflow-core/src/airflow/ui/src/components/MonacoEditor/configureMonaco.ts
@@ -58,53 +58,21 @@ const loadMonacoModules = async () => {
     ),
   ]);
 
-  // The JSON feature registers its language as a side effect. The 
Dag-authoring languages
-  // are registered manually below from their grammar modules instead: Python 
needs its
-  // patched grammar (triple-quoted f-string support) applied before 
registering, which
-  // importing its register module instead would not allow, and the others are 
registered
-  // the same way for consistency.
-  // The runtime guard below fails loudly if a grammar export shape changes.
+  // The JSON feature registers its language as a side effect. Every Monarch 
grammar monaco
+  // ships is registered with a lazy loader, so a grammar chunk is only 
fetched the first time
+  // an editor uses its language: any language id an importer stores for its 
Dag source gets
+  // highlighted without the UI knowing the list up front.
   const jsonContribution = 
import("monaco-editor/languages/features/json/register");
-  const pythonGrammar = 
import("monaco-editor/languages/definitions/python/python");
-  const typescriptGrammar = 
import("monaco-editor/languages/definitions/typescript/typescript");
-  const javaGrammar = import("monaco-editor/languages/definitions/java/java");
-  const goGrammar = import("monaco-editor/languages/definitions/go/go");
-  const yamlGrammar = import("monaco-editor/languages/definitions/yaml/yaml");
-
-  const [
-    monaco,
-    [editorWorkerUrl, jsonWorkerUrl],
-    { conf: pythonConf, language: pythonLanguage },
-    { conf: typescriptConf, language: typescriptLanguage },
-    { conf: javaConf, language: javaLanguage },
-    { conf: goConf, language: goLanguage },
-    { conf: yamlConf, language: yamlLanguage },
-  ] = await Promise.all([
+  const grammarContributions = 
import("monaco-editor/languages/definitions/register.all");
+
+  const [monaco, [editorWorkerUrl, jsonWorkerUrl]] = await Promise.all([
     monacoApi,
     workerUrls,
-    pythonGrammar,
-    typescriptGrammar,
-    javaGrammar,
-    goGrammar,
-    yamlGrammar,
     jsonContribution,
+    grammarContributions,
   ]);
 
-  return {
-    editorWorkerUrl,
-    goConf,
-    goLanguage,
-    javaConf,
-    javaLanguage,
-    jsonWorkerUrl,
-    monaco,
-    pythonConf,
-    pythonLanguage,
-    typescriptConf,
-    typescriptLanguage,
-    yamlConf,
-    yamlLanguage,
-  };
+  return { editorWorkerUrl, jsonWorkerUrl, monaco };
 };
 
 const createWorkerFromUrl = (workerUrl: string): Worker => {
@@ -121,62 +89,32 @@ export const configureMonaco = () => {
   }
 
   configurationPromise = loadMonacoModules()
-    .then(
-      ({
-        editorWorkerUrl,
-        goConf,
-        goLanguage,
-        javaConf,
-        javaLanguage,
-        jsonWorkerUrl,
-        monaco,
-        pythonConf,
-        pythonLanguage,
-        typescriptConf,
-        typescriptLanguage,
-        yamlConf,
-        yamlLanguage,
-      }) => {
-        Reflect.set(globalThis, "MonacoEnvironment", {
-          getWorker: (_moduleId: string, label: string) =>
-            createWorkerFromUrl(label === "json" ? jsonWorkerUrl : 
editorWorkerUrl),
-        } satisfies MonacoEnvironment);
-
-        // The editor always sets the Dag's own language explicitly, so no 
extensions/firstLine
-        // auto-detection metadata is needed for any of these. Guard the 
internal grammar
-        // export shape: if a monaco upgrade drops these, fail loudly here 
rather than
-        // silently disabling highlighting (`setMonarchTokensProvider(id, 
undefined)`).
-        // The `conf`/`language` types come from hand-written ambient 
declarations, so
-        // TypeScript believes they are always defined; this guard checks the 
real runtime
-        // shape the types cannot vouch for.
-        const grammars = [
-          { conf: pythonConf, id: "python", language: pythonLanguage },
-          { conf: typescriptConf, id: "typescript", language: 
typescriptLanguage },
-          { conf: javaConf, id: "java", language: javaLanguage },
-          { conf: goConf, id: "go", language: goLanguage },
-          { conf: yamlConf, id: "yaml", language: yamlLanguage },
-        ] as const;
-
-        for (const grammar of grammars) {
+    .then(({ editorWorkerUrl, jsonWorkerUrl, monaco }) => {
+      Reflect.set(globalThis, "MonacoEnvironment", {
+        getWorker: (_moduleId: string, label: string) =>
+          createWorkerFromUrl(label === "json" ? jsonWorkerUrl : 
editorWorkerUrl),
+      } satisfies MonacoEnvironment);
+
+      // Replaces the lazy Python tokenizer `register.all` set up with the 
patched grammar
+      // (triple-quoted f-string support), still loaded on first use.
+      monaco.languages.registerTokensProviderFactory("python", {
+        create: async () => {
+          const { language } = await 
import("monaco-editor/languages/definitions/python/python");
+
+          // The `language` type comes from a hand-written ambient 
declaration, so TypeScript
+          // believes it is always defined; fail loudly if a monaco upgrade 
drops the export
+          // rather than silently disabling Python highlighting.
           // eslint-disable-next-line 
@typescript-eslint/no-unnecessary-condition
-          if (grammar.conf === undefined || grammar.language === undefined) {
-            throw new Error(
-              `monaco ${grammar.id} grammar module changed shape: missing 
\`conf\`/\`language\` export`,
-            );
+          if (language === undefined) {
+            throw new Error("monaco python grammar module changed shape: 
missing `language` export");
           }
-          monaco.languages.register({ id: grammar.id });
-          monaco.languages.setLanguageConfiguration(grammar.id, grammar.conf);
-          // Python needs the patched grammar (triple-quoted f-string 
support); the rest
-          // register as monaco ships them.
-          monaco.languages.setMonarchTokensProvider(
-            grammar.id,
-            grammar.id === "python" ? patchPythonFStrings(grammar.language) : 
grammar.language,
-          );
-        }
-
-        loader.config({ monaco });
-      },
-    )
+
+          return patchPythonFStrings(language);
+        },
+      });
+
+      loader.config({ monaco });
+    })
     .catch((error: unknown) => {
       configurationPromise = undefined;
       // eslint-disable-next-line no-console
diff --git a/airflow-core/src/airflow/ui/src/vite-env.d.ts 
b/airflow-core/src/airflow/ui/src/vite-env.d.ts
index 5b70be41e1c..0efa1e9c8b0 100644
--- a/airflow-core/src/airflow/ui/src/vite-env.d.ts
+++ b/airflow-core/src/airflow/ui/src/vite-env.d.ts
@@ -25,7 +25,7 @@ interface ImportMeta {
   readonly env: ImportMetaEnv;
 }
 
-// Each of these language definitions exports its Monarch grammar (`conf` / 
`language`)
+// The Python language definition exports its Monarch grammar (`conf` / 
`language`)
 // but ships no `.d.ts` of its own.
 declare module "monaco-editor/languages/definitions/python/python" {
   // `import(...)` type syntax is required here: a top-level `import type` 
would turn this
@@ -35,31 +35,3 @@ declare module 
"monaco-editor/languages/definitions/python/python" {
   export const language: import("monaco-editor").languages.IMonarchLanguage;
   /* eslint-enable @typescript-eslint/consistent-type-imports */
 }
-
-declare module "monaco-editor/languages/definitions/typescript/typescript" {
-  /* eslint-disable @typescript-eslint/consistent-type-imports */
-  export const conf: import("monaco-editor").languages.LanguageConfiguration;
-  export const language: import("monaco-editor").languages.IMonarchLanguage;
-  /* eslint-enable @typescript-eslint/consistent-type-imports */
-}
-
-declare module "monaco-editor/languages/definitions/java/java" {
-  /* eslint-disable @typescript-eslint/consistent-type-imports */
-  export const conf: import("monaco-editor").languages.LanguageConfiguration;
-  export const language: import("monaco-editor").languages.IMonarchLanguage;
-  /* eslint-enable @typescript-eslint/consistent-type-imports */
-}
-
-declare module "monaco-editor/languages/definitions/go/go" {
-  /* eslint-disable @typescript-eslint/consistent-type-imports */
-  export const conf: import("monaco-editor").languages.LanguageConfiguration;
-  export const language: import("monaco-editor").languages.IMonarchLanguage;
-  /* eslint-enable @typescript-eslint/consistent-type-imports */
-}
-
-declare module "monaco-editor/languages/definitions/yaml/yaml" {
-  /* eslint-disable @typescript-eslint/consistent-type-imports */
-  export const conf: import("monaco-editor").languages.LanguageConfiguration;
-  export const language: import("monaco-editor").languages.IMonarchLanguage;
-  /* eslint-enable @typescript-eslint/consistent-type-imports */
-}

Reply via email to