microsoft / microsoft/TypeScript

Design Meeting Notes, 2026-07-23

Offen
#63,676 0 Kommentare 2 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

Design Notes
Vorherrschende Sprache
Go
Sterne
111k
Forks
14.3k
Ø Merge
2 T. 4 Std.
Gemergte PRs (30 T.)
132

Beschreibung

JavaScript Emit API

https://github.com/microsoft/typescript-go/pull/4699

  • How would something like "compile on save" be reimplemented?
    • Idea: LSP has didSave event, clients can listen and trigger a custom emit command
    • Does emit in LSP make sense?
    • We do expect it for the playground.
    • Sounds like yes.
  • Source maps?
    • Should add those too.
  • What's the (internal) API look like?
    • program.emit(emitOnly?: EmitOnly) - file system (including VFS if supplied), whole program, respects emit-blocking options like noEmit, noEmitOnError, ...

      • Some weirdness in interaction, e.g. emitDeclarationOnly
    • program.emitToString(emitOnly?: EmitOnly) - in-memory string results, whole program, respects emit-blocking options

      • Basically a string over IPC
    • program.getJavaScriptEmit(files?: readonly DocumentIdentifier[]) - in-memory string results, specific file selection, bypasses emit-blocking options

      • In-memory, does not respect noEmit, emitDeclarationOnly, etc.
    • program.getDeclarationEmit(files?: readonly DocumentIdentifier[]) - (same)

    • And EmitOnly is:

      export enum EmitOnly {
          All = 0,
          OnlyJs = 1,
          OnlyDts = 2,
      }
      
  • May have to consider how pre/post transformations work here, plus dynamically contributed content - recall that Angular might have been looking for this with ngc?

Content Mappers

// tsconfig.json
{
    "compilerOptions": {
        // ...
    },
    "contentMappers": [
        {
            "package": "vue-content-mapper",
            "extensions": [".vue"],
        }
    ],
    "include": ["src"]
}
// node_modules/vue-content-mapper/package.json
{
    "name": "vue-content-mapper",
    "version": "1.0.0",
    "tsContentMapper": {
        "exec": ["node", "dist/server.js"],
        "compilerOptions": ["module", "jsx", "jsxImportSource"]
    }
}
  • What kind of versioning contract can we provide here?
    • Stuff like LSP/Language Server Protocol doesn't provide a version per se - it's all capabilities based. Looks like same with AHP/Agent Host Protocol.
      • Can keep version, but stick close to that model.
  • Why does this have to be a protocol instead of something like a potentially long-running process? Feels heavy.
    • Don't want to have multiple invocations of the mapper.
    • Cascading resolution: we don't always know which files the program itself includes (you can end up with .vue files outside of the program)
    • Also, we have long-running things like --watch and LSP where the program state will change over time.
    • These transforms are all supposed to be idempotent.
  • One issue is: are these able to react to their configurations, and invalidate their resolution?
    • We can react to the package itself changing, but not currently to configuration.
    • Maybe we need something about config files that the plugin can watch.
  • Do we allow this only for --moduleResolution bundler or for --moduleResolution nodenext and others?
    • It works across everything.
  • Top-level contentMappers field - how does this work with tsconfig inheritance?
    • It currently doesn't.
  • This does have some invasiveness in our LSP implementation.
    • Two different spans in a .ts file can map to the same span in a .vue file.
      • Also, want these operations to coalesce occasionally.
    • So operations at Line X Column Y now potentially have multiple results!
      • So some operations default to the first result (hover), some concatenate results (go-to-definition).
  • This doesn't completely subsume Volar - Volar can mask/fix up errors.
    • But you can build an LSP over this to do this if desired.
  • What are examples of that funky LSP behavior?
    • Take for example:
      <script setup lang="ts">
      import { ref, computed } from "vue";
      
      const count = ref(0); const label = ref("clicks");
      const label = computed(() => count.value === 1 ? "click" : "clicks");
      const doubled = computed(() => count.value *2);
      
      function increment(): void {
        count.value++;
      }
      </script>
      
      <template>
        <div class="counter">
          <p>{{ count }} {{ label }}</p>
          <p>doubled = {{ doubled }}</p>
          <button @click="increment()">+1</button>
          <ul>
            <li v-for="(n, i) in [count, doubled]" :key="i">{{ n }}</li>
          </ul>
          <span v-if="count > 5">high</span>
        </div>
      </template>
      
    • Kinda remaps to...
      // SCRIPT SETUP START:
      
      export default createComponent({
        // ...
        setup(props) {
      
      // VERBATIM-ISH SCRIPT BLOCK:
        const count = ref(0);
        // ...
      
      // GENERATED AFTER SCRIPT:
        return {
          count,
        };
      });
      
      // GENERATED FROM TEMPLATE BLOCK:
      
      function render(props)
        const { count } = props;
      
        // usage of count
        count;
      }
      
    • A reference to count in the <template> block has a definition that doesn't exist in the original .vue source, but also has a mapping to have a mapping back to a node that is not the "true" definition site.

Beitragsleitfaden

Beitragsleitfaden öffnen

Erste Schritte

  1. Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
  3. Forke das Repository und arbeite in einem Branch.
  4. Öffne einen Pull Request, der die Issue-Nummer nennt.

Rechercherichtung

Dies ist ein Protokoll eines Design-Meetings und keine Implementierungsaufgabe; es nennt keine Quelldateien oder Tests. Beginne mit dem Lesen der verlinkten Pull Requests 4699 und 4712 sowie des referenzierten TypeScript-Issue-Kommentars. Für den Abschluss wäre eine vereinbarte JavaScript-Emit-API und ein vereinbarter Umfang des content-mapper-Protokolls erforderlich, bevor Implementierungsarbeit definiert werden kann.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
javascript, typescript
Bereich
compilers, devtools
Issue-Typ
Feature
Schwierigkeit
5/5
Geschätzter Aufwand
Über eine Woche
Aktivitätsstatus
Ruhig
Klarheit
Muss geklärt werden
Anfängerfreundlichkeit
25/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.