Typescript: Plugin-Unterstützung für benutzerdefinierte Transformatoren

Erstellt am 2. März 2017  ·  99Kommentare  ·  Quelle: microsoft/TypeScript

Seit #13764 gelandet ist, ist es einfach, benutzerdefinierte Transformatoren zu schreiben. Wenn ich die API jedoch richtig verstehe, muss die gesamte tsc-Befehlszeile dupliziert werden, nur um einen einzelnen Transformator hinzuzufügen. Dies führt zu Inkompatibilitäten, da diese, je nach Schreibschrift, Anwendungen nicht die gleichen Features wie das tsc-Kommandozeilentool unterstützen.

Es wäre daher wünschenswert, ein Plugin-System zu haben, das das Laden von benutzerdefinierten Transformern aus Node-Modulen von Drittanbietern ermöglicht, wie dies bei den Sprachdienst-Proxys #12231 der Fall ist. Diese Transformer lassen sich dann einfach in bestehende Build-Tools/Build-Workflows integrieren.

Wenn jemand, der erfahren ist, Inputs zur Implementierung der Änderungen hat, bin ich bereit, eine PR zu erstellen, da dies mein Projekt enorm vereinfachen würde.

Docs

Hilfreichster Kommentar

Ich möchte keine exponierte Plugin-API haben. Stattdessen würde ich es vorziehen, meine benutzerdefinierten Transformationen zu registrieren, indem ich sie einfach in der tsconfig.json angebe, anstatt die TS-Compiler-API verwenden zu müssen. Denn die Verwendung der TS-Compiler-API bedeutet, dass ich das tsc-Befehlszeilentool nicht mehr verwenden kann, was ferner bedeuten kann, dass es sich nicht mehr gut in bestehende Build-Tools und Workflows integrieren lässt.

Alle 99 Kommentare

Wir planen nicht, das Compiler-Plug-in-System kurzfristig zu veröffentlichen. Die Transformationen werden, wie Sie bemerkt haben, als Teil der öffentlichen API verfügbar gemacht, und wir sind dabei, Dokumentationen und Beispiele dafür zu schreiben.

Ich möchte keine exponierte Plugin-API haben. Stattdessen würde ich es vorziehen, meine benutzerdefinierten Transformationen zu registrieren, indem ich sie einfach in der tsconfig.json angebe, anstatt die TS-Compiler-API verwenden zu müssen. Denn die Verwendung der TS-Compiler-API bedeutet, dass ich das tsc-Befehlszeilentool nicht mehr verwenden kann, was ferner bedeuten kann, dass es sich nicht mehr gut in bestehende Build-Tools und Workflows integrieren lässt.

irgendetwas Update über Dokumentation und Beispiele? @mhegazy

@MichaReiser Sie können einen einfachen Compiler basierend auf der API schreiben (Beispiel hier ). Wir verwenden TS tatsächlich sehr intensiv innerhalb von Yahoo Finance, und die öffentliche Transformer-API war großartig.

Dies sind einige der Transformatoren, die wir geschrieben haben, nachdem es veröffentlicht wurde:
https://github.com/longlho/ts-transform-system-import
https://github.com/longlho/ts-transform-img
https://github.com/longlho/ts-transform-react-intl
https://github.com/longlho/ts-transform-css-modules-transform

@mhegazy lmk, wenn Sie Hilfe beim Dokumentieren/Sammeln von Proben benötigen

@Longlho
Danke für deine Probe.

Das mache ich gerade. Es macht es jedoch unmöglich, andere Build-Tools zu verwenden, die für Typoskript erstellt wurden, z. B. Web-Pack-Loader, Jest-Loader. Außerdem, wie kann ich eines Ihrer Plugins zusammen mit einem von mir verwenden, wenn jeder von uns ein anderes Frontend verwendet?

Daher glaube ich, dass der aktuelle Ansatz ein guter Anfang ist, aber für ein Plugin-Ökosystem nicht ausreicht. Denn die Nutzung eines Plugins ist für den Nutzer zu aufwändig und erfordert mehr als nur das Schreiben des Transformationscodes für den Autor.

Ich glaube, ein Plugin-System wie das von Babel ist für Typoskript unerlässlich, wenn das Ziel darin besteht, die Community zu ermutigen, benutzerdefinierte Transformatoren zu erstellen und zu verwenden.

@MichaReiser jap . Ich sage nicht, dass es für das Ökosystem ausreicht, nur gut genug für den ersten Schritt dorthin.

Ich würde gerne Unterstützung für Transformationen in gulp-typescript hinzufügen, aber ich möchte verhindern, dass alle TypeScript-Plugins (für gulp, webpack usw.) eine andere API vorschlagen. Und TypeScript fügt möglicherweise später sogar eine andere Möglichkeit hinzu, dies zu konfigurieren. Haben Sie derzeit Pläne, dies in naher oder ferner Zukunft hinzuzufügen?

Hallo zusammen, ich versuche einen Präprozessor zu schreiben, aber es kommt nichts heraus :[

Eigentlich habe ich zwei Fragen:

  • Wie erstelle ich ein AST-Fragment aus einer Zeichenfolge?
  • Wie füge ich Import hinzu?
// 1. Input
class Foo {
    templateString = 'some value';
}

// 2. After transformation
import __LIB__ from '@external/lib';

class Foo {
    templateString = (function compiledTemplate(deps) {
        // ...
        return result;
    })({lib: __LIB__});
}

// 3. Expected result
var lib_1 = require("@external/lib");
var Foo = (function () {
    function Foo() {
        this.templateString = (function compiledTemplate(deps) {
            // ...
            return result;
        })({ lib: lib_1 }); 
    }
    return Foo;
}());

Ein vereinfachtes Beispiel: https://github.com/RubaXa/typescript-api-questions/tree/master/import-add

⬆️ ⬆️ ⬆️
@longlho , @mhegazy Kannst du einen Tipp geben?

@RubaXa Da Sie die Importdeklaration in einer Transformation hinzugefügt haben, ist sie nicht gebunden oder typgeprüft. Da es nicht gebunden oder typgeprüft war, können wir __LIB__ in Ihrem Ausdruck nicht in __LIB__ in der Deklaration auflösen.

Eine Option besteht darin, einen Namespace-Import anstelle eines Standardimports zu verwenden, sodass Ihre Emit in etwa so aussieht:

import * as __LIB__ from "@external/lib"

Da kein Aliasing auftreten kann.

Die anderen halten eine generierte Kennung für die Einfuhranmeldung gemäß der beigefügten Zip -Datei fest

@RubaXa Wenn Sie das gesamte Modulobjekt übergeben möchten, möchten Sie wahrscheinlich die import * as __LIB__ from "@external/lib" -Syntax verwenden (die kein Aliasing erfordert) und nicht import __LIB__ from "@external/lib" , da letztere die default importiert

Ja, wir machen import * as foo auch in unserem CSS-Modultransformator , um Aliasing zu verhindern. Obwohl es schön wäre, darauf zurückzugreifen, um bestimmte benannte Exporte einzufügen

@rbuckton O, vielen Dank!
Immer noch daran interessiert, wie man ein beliebiges AST-Fragment aus einer Zeichenfolge erstellt?

function createFragmentFromString(code: string) {
  // ????
}

function visitPropertyDeclaration(node) {
    if (ts.isIdentifier(node.name) && node.name.text === "templateString") {
        // ...
        return ts.updateProperty(
            node,
            ts.visitNodes(node.decorators, visitor),
            ts.visitNodes(node.modifiers, visitor),
            ts.visitNode(node.name, visitor),
            ts.visitNode(node.type, visitor),
            createFragmentFromString('(function compiledTemplate() { /* ... */ })()')
        );
    }
    return node;
}

Ich hatte gehofft, dass sich die Transformer-Unterstützung und der Workflow so in TypeScript verhalten würden.

https://www.dartlang.org/tools/pub/transformers

Ich interessiere mich auch sehr für diese Funktion.

wie @MichaReiser erwähnt
If someone experienced has inputs on how to implement the changes, I'm willing to create a PR as it would simplify my project tremendously.

Ich freue mich über Beiträge von Experten/Typoskript-Compiler DEV .

Sieht so aus, als hätte jemand Typoskript umschlossen, um diese Funktionalität verfügbar zu machen. https://github.com/cevek/ttypescript

Sieht auch so aus, als hätte ts-loader es: https://www.npmjs.com/package/ts-loader#getcustomtransformers -----before-transformerfactory--after-transformerfactory----

Ich denke, das ist etwas, das irgendwann in Typescript 2.8 oder zumindest in der Roadmap landen könnte, @ahejlsberg @mhegazy @DanielRosenwasser was denkst du? Auf diese Weise könnten benutzerdefinierte Transformatoren beliebter und daher leistungsfähiger sein. Die Möglichkeit, Transformer aus der Perspektive von tsconfig.json einzustecken, würde das Leben erheblich vereinfachen.

Wie bereits erwähnt, haben wir keine Pläne, Plugins kurzfristig bereitzustellen.

@mhegazy Ist es eine wohlüberlegte Entscheidung oder liegt es nur wegen des geringen Interesses der Community außerhalb des Geltungsbereichs?

Das habe ich nicht gesagt. Wir möchten geringe öffentliche API-/Wartungskosten sowie Flexibilität bei der Änderung der Art und Weise, wie der Build vorangetrieben wird, beibehalten, und beides wird von einem Plugin-Modell beeinflusst.

Bitte stoppen Sie die Fragmentierung der Transformer-Plugin-API. Stabilisieren Sie die Plugin-API auf der Transformer-API und stellen Sie sie in tsconfig.json bereit.

ts-loader , packet-plugin- typescript , rollup-plugin-typescript2 , ts-transformer-keys , ttypescript und andere.

Jeder von ihnen bietet eine benutzerdefinierte Plugin-Registrierungsmethode und ein benutzerdefiniertes Plugin-Einstiegspunktformat. Es ist ein Weg in die TS-Plugin-Hölle.

Jetzt unterstützt cevec/ttypescript alle gängigen Transformer-Plugin-Formate. Es ist ein Drop-In-Wrapper auf allen Typescript-Modulen und tsc-, tsserver-Befehlen (nur ein kleiner Runtime-ts.createProgram-Patch). Webpack ts-loader und rollup-plugin-typescript2 können einfach mit ttypescript konfiguriert werden.

TTypescript schlägt ein universelles Transformer-Plugin-Format vor, aber vorhandene Transformer werden ebenfalls unterstützt.

{
    "compilerOptions": {
        "plugins": [
            { "transform": "ts-transform-graphql-tag" },
            { "transform": "ts-transform-css-modules", "type": "config" },
            { "transform": "ts-nameof", "type": "raw", "after": true}
            { "transform": "./transformers/my-transformer.ts", "someOption1": 123, "someOption2": 321  }
        ]
    },
    "exclude": ["node_modules", "transformers/**/*"]
}

Irgendwelche Neuigkeiten zu diesem? Scheint mir, als wollten TypeScript-Autoren irgendwie keine benutzerdefinierten Transformatoren auf Vanilla-TypeScript zulassen - das ist eine Schande, es wäre eine großartige Funktion.

Sie wollen nicht, dass eine andere API/Oberfläche gewartet wird, aus Angst, dass es zu Schwierigkeiten kommt, Dinge in den Interna zu beschädigen. Ironischerweise sind all diese Plugin-Lösungen von Drittanbietern, weil es keinen Standard vom ts-Team gibt, alle etwas anders und werden irgendwann kaputt gehen.

Sie wollen nicht, dass eine andere API/Oberfläche gewartet wird, aus Angst, dass es zu Schwierigkeiten kommt, Dinge in den Interna zu beschädigen.

Nachdem ich drei Jahre lang mit Typoskript gearbeitet und seine Entwicklung beobachtet habe, bin ich zu einem einfachen Schluss gekommen. Microsoft hat Typescript im Sinne des _Codes_ offengelegt, aber nicht im Sinne des _Prozesses_. In den meisten Fällen sind Open-Source-Projekte sowohl in den Entscheidungen als auch in der Codierung mehr oder weniger von der Community angetrieben, und dies sollte der natürliche Weg sein, sich weiterzuentwickeln. Erinnern Sie sich an den IO.js-Fork von node.js? Die Community erkannte, dass die Unternehmensinteressen nicht so sehr mit dem gemeinsamen Open-Source-Governance-Modell übereinstimmten, und sie teilten sich einfach auf. Ich hoffe, dass dies bei TypeScript nicht passieren wird, aber Microsoft sollte diese Möglichkeit berücksichtigen.
Um es klar zu sagen, ich gebe den Entwicklern sowieso keinen Vorwurf, sie machen wirklich einen tollen Job.
Nur meine 2c, sorry für das OT.

Microsoft hat Typescript im Sinne des Codes quelloffen gemacht, aber nicht im Sinne des Prozesses.

Dem stimme ich ausdrücklich nicht zu. Ich habe nie für Microsoft gearbeitet, aber ich hatte in den letzten 4 Jahren direkten Einfluss auf mehrere Features von TypeScript. Ich vertrat eine Open-Source-Bibliothek, die in TypeScript erstellt wurde, und wir vereinbarten, einige direkte Gespräche zu führen, aber die gesamte „Debatte“ über alle Funktionen wurde hier offen und öffentlich geführt. Das Kernteam veröffentlicht seine Design-Meeting-Notizen. Der einzige „Insider“, den ich bekam, der eine Open-Source-Bibliothek vertrat, war die Gelegenheit, meinen Standpunkt für einige Funktionen persönlich zu vertreten und das Kernteam kennenzulernen. Mir wurde klar, dass das Team als Team agiert. Ein Feature, über das wir gesprochen haben, Anders sagte im Grunde, das Problem sei zu schwer und es würde viel Zeit kosten, es zu lösen und die "echten" Probleme zu lösen, mit denen die Leute konfrontiert sind. Das war vor zwei Jahren und in TypeScript 3.0 haben wir es endlich hinbekommen. Aber die Community hat eine Stimme im Designprozess, aber wie jede Community haben wir verschiedene Stimmen, und kein Team könnte es allen recht machen, und wenn sie es täten, wäre TypeScript ein _wirklich_ schlechtes Werkzeug.

Sie wollen das Kernteam auch „Microsoft“ nennen. Das Kernteam war das kleinste Microsoft-Team, dem ich je begegnet bin. Sie kämpften um die vollständige Kontrolle über ihre Veröffentlichungskadenz, nachdem sie die volle Kontrolle über ihre Veröffentlichungsinhalte erlangt hatten. Sie kämpften auch für Offenheit und Transparenz. Sie haben darum gekämpft, von CodePlex zu GitHub zu wechseln. Zugegeben, sie sind bei Microsoft nicht mehr so ​​einzigartig, da mehrere andere Teams ihr Modell übernommen haben, aber soweit ich weiß, waren sie diejenigen, die alles begonnen haben, wobei das VSCode-Team kurz darauf folgte.

Nur weil das Kernteam seine Schlachten auswählt und sich an ihre Designprinzipien hält, heißt das nicht, dass die Community keine Stimme hat, aber als Stimme leiden wir unter einer psychotischen multiplen Persönlichkeitsstörung. Wir sind ein schwierig zu bedienender Kunde.

Mein Verständnis ist, dass dies dasselbe ist wie #16607, oder würde dies ein anderes Ziel erreichen? Als neuer Plugin-Autor selbst würde ich dies auch gerne offen sehen – auch wenn ich mit TypeScript unter Verwendung des Babel-Plugins arbeite.

@mrmckeb Dieses Problem dient der Standardisierung und Offenlegung der bereits vorhandenen Typoskript-AST-Transformation, während das verknüpfte Problem die gesamte Dateitransformation in einem sehr breiten (undefinierten) Bereich zu diskutieren scheint.

Ich möchte hier meine 2 Cent hinzufügen. Einige von Ihnen haben vielleicht schon von dem brillanten Projekt babel-plugin-macros gehört. Im Grunde kann es anstelle von Tausenden verschiedener Babel-Plugins das einzige geben, das dann von einem Benutzercode angetrieben wird, um eine Transformation durchzuführen. Ein unglaublich transparentes System, ohne dass man sich ständig mit der Konfiguration herumschlagen muss. Dies ist besonders gut für Projekte wie CRA , das Makros unterstützt, aber zusätzliche Konfigurationen verbietet.

Heute habe ich die Diskussion darüber eröffnet, wie man dies möglicherweise in die TypeScript-Welt bringen kann. Wenn Sie einen Einblick haben, kommen Sie bitte und teilen Sie ihn.

Letztendlich hoffe ich, dass, wenn wir irgendwie erfolgreich sind, dies nicht nötig sein wird, da nur eine Transformation erforderlich sein wird.

@FredyC das ist ein cooles Projekt, aber wir müssten dieses Problem lösen, um so etwas einfach in den Compiler einzufügen, wenn nur tsc verwendet wird. Zum Beispiel muss es bei babel-plugin-macros immer noch in .babelrc angegeben werden, und es wäre schön, so etwas in Typoskript in tsconfig.json anzugeben .

Wollen Sie eigentlich sagen, dass es schön wäre, ein Babel-Plug-in-Makro-ähnliches Verhalten in TypeScript integriert zu haben und keine Konfiguration erforderlich wäre? Das mag nett sein, aber ich persönlich würde eine konfigurierbare Lösung bevorzugen, die es ermöglicht, benutzerdefinierte Transformatoren in tsconfig.json anzugeben , und dann könnte eine Version von babel-plugin-macros angegeben werden, die Typskript-Ast-Knoten unterstützt.

@dsherret Ja, ich erwarte nicht, dass es ein Teil von TypeScript selbst ist. Ich kann mir jedoch vorstellen, dass es, sobald die Transformation fertig ist, einfach sein könnte, einen tsc -ähnlichen winzigen Wrapper vorzubereiten, der nur diese Transformation für Makros einfügt und der Rest aus einem Benutzercode erfolgen könnte.

Bearbeiten: Eigentlich ist der winzige Wrapper bereits da, mit dem oben erwähnten https://github.com/cevek/ttypescript wäre es einfach anzuweisen, ihn zusammen mit dem universellen Makro-Plugin zu verwenden, und es ist eine Win-Win-Situation.

Ich muss nur Leute finden, die sich mit Typoskript-Transformationen auskennen, um einen einfachen Prototyp zu erstellen. Ich kann diskutieren und reden, aber die Umsetzung übersteigt meine derzeitigen Fähigkeiten.

Sie wollen nicht, dass eine andere API/Oberfläche gewartet wird, aus Angst, dass es zu Schwierigkeiten kommt, Dinge in den Interna zu beschädigen.

Nachdem ich drei Jahre lang mit Typoskript gearbeitet und seine Entwicklung beobachtet habe, bin ich zu einem einfachen Schluss gekommen. Microsoft hat Typescript im Sinne des _Codes_ offengelegt, aber nicht im Sinne des _Prozesses_. In den meisten Fällen sind Open-Source-Projekte sowohl in den _Entscheidungen_ als auch in der _Codierung_ mehr oder weniger von der Gemeinschaft angetrieben, und dies sollte der natürliche Weg sein, sich weiterzuentwickeln. Erinnern Sie sich an den IO.js-Fork von node.js? Die Community erkannte, dass die Unternehmensinteressen nicht so sehr mit dem gemeinsamen Open-Source-Governance-Modell übereinstimmten, und sie teilten sich einfach auf. Ich hoffe, dass dies bei TypeScript nicht passieren wird, aber Microsoft sollte diese Möglichkeit berücksichtigen.
Um es klar zu sagen, ich gebe den Entwicklern sowieso keinen Vorwurf, sie machen wirklich einen tollen Job.
Nur meine 2c, sorry für das OT.

Ich stimme zu. Es ist klar, dass die Entwickler trotz des starken Interesses der Community die Idee benutzerdefinierter Transformatoren/Makros einfach ablehnen, ohne tatsächlich einen Grund für die Ablehnung anzugeben, außer etwas in der Art von „Die Leute werden es missbrauchen“, was auch gegenüber der Community beleidigend klingt Wie es impliziert, handelt es sich um eine Community von Entwicklern geringer Qualität.

Ich würde eine Ablehnung akzeptieren, wenn eine andere vernünftige Begründung als "Wir werden es nicht einfach tun" geliefert werden könnte, aber anscheinend hat sich trotz aller Anfragen aus der Community noch niemand die Mühe gemacht, dies zu tun.

Ich denke, das ist unfaire Kritik @pietrovismara. Ich stimme zu, dass dies eine unverzichtbare Funktion ist, aber dies ist nicht „Microsoft“, das diese Funktion blockiert. Soweit ich weiß, sagt das Team, dass dies nicht einfach zu unterstützen ist, und deshalb haben sie eine solche Funktion noch nicht hinzugefügt.

Auch hier möchte ich diese Funktion genauso sehr wie jeder andere - aber wir müssen dieses Problem anhand von Fakten diskutieren. Tatsache ist, dass das Team noch nicht bereit ist, es zu unterstützen. Lasst uns also weiterhin Interesse bekunden, aber auch das Gespräch auf dem richtigen Weg halten.

@mrmckeb Wenn das der Fall ist, kann ich es verstehen. Ich muss eine solche Erklärung in der großen Flut von Kommentaren in diesen Ausgaben damals übersehen haben. Wollte niemanden beleidigen, sondern nur versuchen, eine klare Antwort von Mantainern zu provozieren, um, wie Sie sagten, das Gespräch auf dem richtigen Weg zu halten.

Es ist in Ordnung, es ist frustrierend, dass die Unterstützung dafür nicht existiert - wie gesagt, ich fühle es, und wir werden bei CRA die ganze Zeit nach einer Art Lösung für CSS-Module gefragt, jetzt, wo wir TypeScript-Unterstützung haben. Ich hoffe, es kommt bald, aber ich verstehe auch, dass es ein riesiges Risikofeld für das Team eröffnet.

... warte noch :(

ja, immer noch warten ..., aber warten auf was, wurde etwas getan?

Gibt es jetzt eine bessere Lösung als ttypescript ?
Planen TypeScript-Entwickler schließlich, Plugins zu unterstützen?

Sie können Ihren eigenen Compiler erstellen ;-)

Irgendwelche Neuigkeiten zum Thema? Es scheint mir, dass die Community dieses Feature ausgiebig genug genutzt hat, um sich hinzusetzen, Feedback zu sammeln und schließlich die Unterstützung für Transformatoren in die Konfigurationsdatei aufzunehmen. Es gibt sogar viele Implementierungen, die Sie als Referenz verwenden können.

Es ist über 2 Jahre her (wow!)*. Sind die Leute bereit, die Vor- und Nachteile der Öffnung von Plugins für Transformatoren zu überdenken?

Ich habe das Gefühl, dass die anfänglichen Bedenken, die vor all dieser Zeit bestanden haben, wie fehlende Dokumentation über die API und die Notwendigkeit, die Vernetzung von Benutzercode <-> Transformatoren <-> API zu unterstützen, nicht mehr so ​​​​relevant sind. Die Unterstützung offener Plugins hat bei Paketen wie babel Wunder gewirkt: Fortschritt durch Zusammenarbeit. Ich kann Babel persönlich bestätigen, da ich es ausgiebig benutzt habe.

Einfachere "funktioniert einfach"-Integration von Transformern wie Typoskript-ist _wäre schön_. Insbesondere dieses Paket hat meiner Meinung nach den revolutionären Einfluss auf das Typoskript als Ganzes. Wahre starke Verträge! 😃

Ich denke, ein Gespräch über die Vor- und Nachteile würde helfen, jegliche Niedergeschlagenheit oder Meinungsverschiedenheiten darüber zu zerstreuen. Ich habe das Gefühl, dass dieses Zombie-Problem weitergehen wird, bis so etwas passiert - um ehrlich zu sein.

* Und in der Zwischenzeit hat jemand stattdessen das Feature für TS erstellt ( ttypescript ). Ich habe dies zum Erfolg verwendet.

@DanielRosenwasser Ich habe gesehen, dass es im 3.5-Iterationsplan "Investigate TypeScript Plugin APIs" gibt (und dass die Arbeit daran bereits begonnen hat).
Handelt es sich bei diesem Punkt um das, was in dieser Ausgabe besprochen wird? Das Fehlen eines Links zu einem Problem lässt mich annehmen, dass es zu viel WIP ist, um noch etwas darüber zu teilen?

Ich denke, dass daran gearbeitet werden sollte, den Babel-Parser vollständig zu unterstützen, was das Hinzufügen notwendiger Funktionen für Babel zur Unterstützung der statischen Typescript-Analyse (z. B. mehrere Dateitransformationen oder Abhängigkeit von mehreren Dateien während der Transformation) umfasst. Anstatt die Syntax zu duplizieren/Babel-Plugins in Typescript-Äquivalente umzuwandeln.

Falls Sie Probleme mit der folgenden Anleitung haben, lassen Sie es mich wissen, ich helfe Ihnen gerne weiter

Angesichts der bloßen Fahrlässigkeit des Designteams ist hier eine Problemumgehung

Wir werden tslint und seine Code-Fixing-Funktionen nutzen

Im folgenden Beispiel führen wir eine Typ-zu-Code-Transformation in ihrer einfachsten Form durch

Wir werden Dekorateure als Markierungen für Stellen im Code verwenden, die umgeschrieben werden müssen

In unserem Fall ist ein Decorator eine gefälschte Funktion, deren einziges Ziel es ist

  • um einen Ort der Transformation zu markieren
  • und um den Typ zu erfassen, der die Informationsquelle für den Generator sein wird

Zu Demonstrationszwecken werden wir die Namen und Typen von Eigenschaften einer Schnittstelle als einfache Zeichenfolgen in eine zugrunde liegende Klasse ausgeben

Die folgenden Schritte sind nur für Windows-Benutzer, wenn Sie keiner von ihnen sind, möge Gott Ihnen helfen:

  1. Starten Sie Ihren VSCode
  2. Installieren Sie die folgende Erweiterung: https://github.com/Microsoft/vscode-typescript-tslint-plugin
  3. Schließen Sie Ihren VSCode
  4. Gehen Sie zu einem Ordner Ihrer Wahl
  5. Führen git clone https://github.com/zpdDG4gta8XKpMCd/code-gen.git aus
  6. Gehen Sie zum Ordner code-gen : cd ./code-gen
  7. Lauf

    • 1-install.bat

    • 2-build.bat

    • 3-install-some-more.bat

    • 4-try.bat

  8. Beobachten Sie eine geöffnete Instanz von VSCode
  9. gehe zu test.ts ( Ctrl + P -> test.ts )
  10. Beachten Sie die folgende Schnittstelle, sie wird die Quelle für den Codegenerator sein
interface Data {
    one: string;
    another: number;
}
  1. Beachten Sie die folgende Funktion, die einen Phantom-Dekorator enthält, den wir als Markierung verwenden werden
function gen<_T>() {
    return function (meh: any) {};
}
  1. Beachten Sie die Website zum Umschreiben, wo wir etwas automatisch generierten Code basierend auf der Schnittstelle und dem Marker-Decorator einfügen möchten
@gen<Data>()
export class Gen {
}
  1. Beachten Sie eine verschnörkelte Linie unter @gen<Data>()
    image

  2. Wählen Sie Quick fix... -> Needs a rewrite, wanna fix?
    image

  3. Beachten Sie den automatisch generierten Code:
    image


als Referenz hier der Quellcode des Generators, den Sie in codeGenRule.ts finden können

import * as Lint from 'tslint';
import * as ts from 'typescript';

export class Rule extends Lint.Rules.TypedRule {
    public applyWithProgram(sourceFile: ts.SourceFile, program: ts.Program): Lint.RuleFailure[] {
        return this.applyWithWalker(new Walker(sourceFile, this.getOptions(), program.getTypeChecker()));
    }
}

class Walker extends Lint.RuleWalker {
    constructor(sourceFile: ts.SourceFile, options: Lint.IOptions, private checker: ts.TypeChecker) {
        super(sourceFile, options);
    }
    public visitNode(node: ts.Node) {
        if (ts.isDecorator(node)) {
            const checked = check(node, this.checker);
            if (checked !== undefined) {
                const [node, message, replacement] = checked;
                this.addFailureAtNode(node, message, replacement);
            }
        }
        super.visitNode(node);
    }
}

function check(node: ts.Decorator, checker: ts.TypeChecker) {
    const { expression, parent } = node;
    if (!ts.isClassDeclaration(parent)) return;
    if (!ts.isCallExpression(expression)) return;
    const { expression: identifier, typeArguments: typeArgs } = expression;
    if (!ts.isIdentifier(identifier)) return;
    const { text: name } = identifier;
    if (name !== 'gen') return;
    if (typeArgs === undefined) return;
    if (typeArgs.length > 1) return;
    if (typeArgs.length < 1) return;
    const [only] = typeArgs;
    const type = checker.getTypeFromTypeNode(only);

    // if you got to here, you are at the right place and you have a type

    // working on a fix
    const properties = checker.getPropertiesOfType(type);
    const allNameTypes = properties.map(p => {
        const { name } = p
        const type = checker.getTypeOfSymbolAtLocation(p, node);
        return name + ': \'' + checker.typeToString(type) + '\';'
    })
    const { newLine } = ts.sys;
    const body = newLine + allNameTypes.join(newLine);
    const { pos: start, end } = parent.members;
    return [
        node,
        'Needs a rewrite, wanna fix?',
        Lint.Replacement.replaceFromTo(start, end, body)
    ] as const;
}

@zpdDG4gta8XKpMCd , danke, dass du dein Konzept geteilt hast – aber sei bitte höflich.

Angesichts der bloßen Fahrlässigkeit des Designteams ist hier eine Problemumgehung

Dies ist nicht der richtige Weg, um TypeScript anzusprechen, weil es ein _Feature_ nicht implementiert, das Sie (und viele andere, mich eingeschlossen) gerne hätten. Dies ist kein wesentlicher Mangel und spiegelt keine "Fahrlässigkeit" wider. Bitte seien Sie respektvoll.

oh bitte nimm es nicht persönlich, so beginne ich immer meine Beschwerden, ich habe eine sehr schlechte Persönlichkeit (Krankheit) und das ist das Beste, was ich aus mir herauspressen kann, es tut mir sehr leid

Sie werden nicht aufhören, mich zu überraschen

  • Was Sie sehen, ist ein Stück Code, das in der Lage zu sein scheint, ein großes heutiges Problem bequem zu lösen (keine Tricks, kein Hacken).
  • Diese Problemumgehung ist ein Weckruf für das Designteam, und wie wir es zuvor gesehen haben, als die Community kurz davor stand, in eine falsche Richtung abzubiegen, war das Designteam da, um es umgehend anzugehen: #4212,
  • Wenn es ihnen also wichtig ist, können sie es eher früher richtig machen, bis es zu spät ist, oder wenn sie es nicht tun, können wir in diese Richtung graben, und es wird später kein Problem für sie sein
  • Der Ton meines Feedbacks war also etwas unangemessen, aber all der angemessene Ton von Ihnen hat Ihnen seit dem 2. März 2017 (über 2 Jahre) nichts gebracht, und ja, Sie können weitere 2 Jahre warten

@zpdDG4gta8XKpMCd Was hast du zu einer tatsächlichen Implementierung beigetragen? TypeScript ist Open Source; Ich habe keinen Zweifel, dass sie ernsthaft einen Pull-Request in Betracht ziehen würden, wenn Sie einen erstellen (auch nur teilweise).

Es ist inakzeptabel, Ihre Unhöflichkeit einem medizinischen Zustand zuzuschreiben; Es handelt sich um Wörter, die Sie eingegeben und freiwillig ausgewählt haben, um auf "Kommentar" zu klicken. Keine Krankheit zwingt Sie dazu. Vielleicht sprechen, nicht tippen. Sie hatten auch die Möglichkeit, Ihren Kommentar zu bearbeiten, um ihn zu entfernen, haben dies jedoch nicht getan.

Wenn Sie benutzerdefinierte Transformer _jetzt_ benötigen, können Sie Babel verwenden. Es kann Typanmerkungen aus fast allen TypeScript-Dateien entfernen, während Syntaxtransformationen so einfach möglich sind, wie Sie möchten. Als Bonus ist es auch schneller.

Ich schlage vor, Sie hören auf zu kommentieren, bevor Sie dauerhaft aus dem Repository von Microsoft geworfen werden. Ich weiß, wenn es mein Repo wäre, wärst du am Ende.

ok, du hast mich rausgeschmissen, was dann
Kann ich jemals zurückkommen? kann ich ein neues Konto erstellen?
Glaubst du, ich interessiere mich zu sehr für dieses Konto?

Wie auch immer, ja, ich habe es mit Pull-Requests versucht, leider ist es aus folgenden Gründen nicht machbar:

  1. Es gibt eine bestimmte Kategorie von Problemen, die Sie gerne lösen können, die eher trivial und weniger interessant sind, alles Ernste wie dieses - und Sie sind es nicht

  2. Da Sie es nicht alleine lösen können, kann ein Problem wie dieses (selbst mit 224 Daumen nach oben) Jahre warten, wenn es überhaupt jemals in Betracht gezogen wird

  3. Glücklicherweise können Sie heute etwas tun, indem Sie alle Mittel verwenden, die Sie haben, und anfangen, einen sichtbaren Unterschied zu machen, daher der Vorschlag (geben Sie mir nicht die Schuld, dass ich nichts getan habe).

@zpdDG4gta8XKpMCd Soviel du weißt, war ich im Laufe der Jahre ein Fan der zynischen Takes, ich muss anderen hier zustimmen – wir müssen das Gespräch höflich und respektvoll führen. Es ist immer eine gute Erinnerung daran, dass jeder, der dieses Problem verfolgt, das Projekt verbessern möchte .


@Janpot Yup , es ist sehr viel ein WIP, aber wenn @rbuckton zurückkommt, kann er vielleicht mehr Details zum Status geben.

Während wir Plugin-Punkte untersuchen (wie ich im 3.5-Iterationsplan angedeutet habe), denke ich, dass das Offenlegen einfacherer Hooks für benutzerdefinierte Transformatoren ein wichtiges Szenario ist, das wir in Betracht ziehen möchten. Der Grund, warum wir dies nicht unbedingt direkt tun würden, ist, dass wir möglicherweise umfassendere Arbeiten haben, die dies zusammenfassen. Mit anderen Worten, vielleicht gibt es etwas Breiteres als nur Vor- und Nachtransformatoren.

@DanielRosenwasser da ist nicht so viel zynisch drin, ich hab nur 2 worte gesagt und dann gesagt das es mir zutiefst leid tut

Wie auch immer, ich denke, wir sind uns alle einig, dass es einen guten Teil gesunder Frustration darüber gibt, wie die Dinge laufen, und wir geben Ihnen keine Schuld, wir verstehen, was dieses Projekt antreibt

aber wenn wir es von unserem Standpunkt aus betrachten, muss es jemanden geben, der schuld ist, denn wenn wir Probleme wie dieses über Jahre hinweg ruhen lassen und nur Daumen hoch sammeln, ist das, was davon abhält, produktiver zu sein

Ich bin mir sicher, dass es Gründe gibt, es aufzuschieben und sich zuerst auf andere Dinge zu konzentrieren, also denke ich, dass es besser wäre, wenn Sie Ihr Publikum wissen lassen würden, warum bestimmte sehr erwünschte Funktionen nicht erfüllt werden können, es könnte den Grad der Frustration verringern, sagen Sie:

  • Wir können diese Funktion nicht implementieren, da A, BC und diese zuerst D, E und F ausführen müssen

Ich denke, ich beziehe mich auf diese Konversation: https://github.com/Microsoft/TypeScript/issues/30696#issuecomment -478799258

Daumen hoch zu haben, schafft nicht neue Ressourcen aus dem Nichts, macht komplexe und schwierige Entscheidungen einfach und leicht, ändert bestehende Geschäftsprioritäten, stoppt laufende Projekte, räumt anderen Arbeiten die Priorität ein, führt nicht dazu, dass übermäßig ehrgeizige Vorschläge zu weitreichend werden, oder Ändern Sie einen Vorschlag mit weitreichenden und dauerhaften Auswirkungen, um zielgerichtet und durchführbar zu werden.

Ich entschuldige mich nicht dafür, dass wir im Voraus gut verstandene, gute und einfache Arbeit leisten (oder PRs für zulassen, worüber Sie sich in #30696 beschwert haben) vor extrem komplexen und wartungsintensiven Arbeiten wie dieser. Es sollte nicht schwer zu erraten sein, warum wir bereit sind, jemanden hereinkommen zu lassen, der einen undichten Wasserhahn repariert, während die Pläne, den Keller umzugestalten und ein weiteres Stockwerk auf dem Dach des Hauses hinzuzufügen, noch ausgearbeitet werden.

@zpdDG4gta8XKpMCd Warum solltest du jemandem die Schuld geben? Warum gibst du dir nicht von vornherein die Schuld, dass du keine PR gemacht hast, um dieses Problem zu beheben? Oder zumindest ein konstruktives Schreiben darüber, wie man es aus Sicht der Implementierung angeht?

Oh Mann, selbst nach diesem transparenten Bericht, den du gerade verlinkt hast, hast du dich entschieden, den Bären nach nur 2 Wochen wieder zu stupsen? Versuchen Sie sich vorzustellen, in dieser Position zu sein und mehr als 1500 Aufgaben zur Hand zu haben, und Sie müssen ein paar davon auswählen. In unserem Team bewegen wir ungefähr 100 Aufgaben und kämpfen ziemlich genug. Kann mir nicht vorstellen, dass es 15 mal mehr wäre 😮

@FredyC , um Gottes willen, schau dir meine Problemumgehung an, bevor du sagst, dass ich nichts tue

Ja, ich mache keine formellen Pull-Requests, weil:

  1. Ich bin nicht auf der Höhe, um einen guten zu machen

  2. Für einfache gibt es eine lange Reihe von Genehmigungen, und es erfordert enorme Arbeit, eine vor 2 Jahren erstellte Pull-Anforderung mit der aktuellen Codebasis auf dem neuesten Stand zu halten. Ich habe nicht so viel Zeit

  3. bestimmte probleme werden angesichts der großen designüberlegungen, die nur wenigen menschen wie anders hejlsberg bewusst sind, nicht einmal berücksichtigt

Sie können mir den Frust nicht nehmen, und ich bin hier nicht allein

Wir wissen, dass diese Faktoren eine Rolle spielen:

  • großartige Gestaltung der Sprache
  • Budget / Ressourcen / Politik innerhalb von MS
  • Wünsche der Gemeinde

Ich würde mich freuen, wenn die Entscheidungsfindung bei der Mischung dieser Zutaten etwas klarer wäre

Ich bin fertig, es ist zu weit gegangen, sorry an alle, deren Gefühle verletzt wurden, ich werde kein Wort sagen

Fortsetzung von https://github.com/Microsoft/TypeScript/issues/14419#issuecomment -483920640

Eine andere Möglichkeit besteht darin, Funktionsdeklarationen selbst als Markierungen zu verwenden. Nachfolgend finden Sie eine Implementierung eines Codegenerators für Funktionen, deren Namen mit toRandom... beginnen

die Informationsquelle für den Generator ist der Ergebnistyp der Funktion

so funktioniert es:

  1. Beachten Sie die verschnörkelte Linie unter einer Funktion, die mit toRandom... beginnt
    image
  2. erkunden Sie Ihre Möglichkeiten:
    image
  3. schnell Abhilfe schaffen
    image
  4. beobachte die ergebnisse:
    image

Hier ist der Code von codeGenRule.ts , der es tut

Als Bonus wird diese Implementierung nur dann ein Linting-Problem aufwerfen, wenn der aktuelle Code der Funktion nicht mit dem Code übereinstimmt, der generiert werden soll

import * as Lint from 'tslint';
import * as ts from 'typescript';

export class Rule extends Lint.Rules.TypedRule {
    public applyWithProgram(sourceFile: ts.SourceFile, program: ts.Program): Lint.RuleFailure[] {
        return this.applyWithWalker(new Walker(sourceFile, this.getOptions(), program.getTypeChecker()));
    }
}

class Walker extends Lint.RuleWalker {
    constructor(sourceFile: ts.SourceFile, options: Lint.IOptions, private checker: ts.TypeChecker) {
        super(sourceFile, options);
    }
    public visitFunctionDeclaration(node: ts.FunctionDeclaration) {
        const checked = check(node, this.checker);
        if (checked !== undefined) {
            const [node, message, fix] = checked;
            this.addFailureAtNode(node, message, fix);
        }
        super.visitFunctionDeclaration(node);
    }
}

function check(node: ts.FunctionDeclaration, checker: ts.TypeChecker) {
    const { name: identifier, type: result, body } = node;
    if (body === undefined) return;
    if (identifier === undefined) return;
    const { text: name } = identifier;
    if (!name.startsWith('toRandom')) return;
    if (result === undefined) return;
    const type = checker.getTypeFromTypeNode(result);

    // if you got to here, you are at the right place and you have a type

    // working on a fix
    const properties = checker.getPropertiesOfType(type);
    const newerBody =
        `{
    return {${properties.map(prop => {
            const { name } = prop;
            const type = checker.getTypeOfSymbolAtLocation(prop, node);
            const typeName = capitalize(checker.typeToString(type));
            return `
        ${name}: toRandom${typeName}(),`;
        }).join('')}
    };
}`;
    const olderBody = body.getFullText();
    if (areEqual(olderBody, newerBody)) return;
    const start = body.getFullStart();
    const end = start + body.getFullWidth();
    return [
        node,
        'Needs a rewrite, wanna fix?',
        Lint.Replacement.replaceFromTo(start, end, newerBody),
    ] as const;
}

function areEqual(one: string, another: string) {
    // AB: we cannot make any assumption what line endings are,
    // this is why we compare the text of code without them
    return one.replace(/\r\n|\n/g, ' ') === another.replace(/\r\n|\n/g, ' ');
}

export function capitalize(value: string): string {
    const length = value.length;
    if (length > 1) {
        return value.substr(0, 1).toUpperCase() + value.substr(1);
    } else if (length > 0) {
        return value.substr(0, 1).toUpperCase();
    } else {
        return value;
    }
}

@zpdDG4gta8XKpMCd Ich glaube, bei diesem Problem ging es eher darum, eine einfachere Möglichkeit zu haben, benutzerdefinierte Transformatoren während des Emittierens anzuschließen? Ex. Angeben von Transformationen in tsconfig.json, damit sie mit tsc verwendet werden können, anstatt die api zu verwenden. Möchten Sie benutzerdefinierte Codeänderungen/Korrekturen im Editor?

Ich habe sie überhaupt nicht verwendet, aber ich denke, das, wovon Sie sprechen, könnte bereits mit einem Sprachdienst-Plugin möglich sein (ich denke, indem Sie getCodeFixesAtPosition für den Sprachdienst überschreiben und Ihre eigenen Codeaktionen einfügen ... bin mir aber nicht sicher) https://github.com/Microsoft/TypeScript/wiki/Writing-a-Language-Service-Plugin

Oder verstehe ich das vielleicht falsch?

rechts. genau das dachte ich früher

Ich dachte, dass eine Möglichkeit, meine benutzerdefinierten Transformationen über tsconfig.json anzugeben, ein wahr gewordener Traum wäre

aber dann habe ich gemerkt, dass mir mein Workaround noch besser gefällt

hier mein gedankengang:

  • Ich brauchte einen steckbaren konfigurierbaren Codegenerator
  • Typoskript hat so etwas nicht zur Hand
  • Auf der anderen Seite weiß ich, dass tslint (obwohl bis Ende 2019 abgeschrieben) eine anständige Plugin-Plattform zum Typoskript ist, die eine Möglichkeit bietet, Ihren Code mit großer Freiheit zu integrieren und zu konfigurieren
  • stellt sich heraus, es hat alles, was ich brauche:

    • steckbar und konfigurierbar

    • mit allen notwendigen UI

    • gibt mir eine API zum Typoskript

    • hat ein paar kleine Extras

Angesichts dessen kann ich mir nicht vorstellen, etwas zu schreiben, das den Typoskript-Sprachdienst verwendet, weil:

  • Mein Laptop kann nur so viele Typoskript-Sprachdienste aufnehmen, und einige davon sind bereits:

    • eine von vscode

    • einer von tslint

und ich möchte nicht noch einen draufsetzen

Ich wünschte, ich hätte eine bessere Möglichkeit, meine Code-Transformatoren einzustecken, aber wir haben, was wir haben


und so machen wir Makros: #4892

  • Mein Laptop kann nur so viele Typoskript-Sprachdienste aufnehmen, und einige davon sind bereits:

    • eine von vscode
    • eine von tslint

@ zpdDG4gta8XKpMCd Ich glaube, alles sollte denselben Sprachdienst verwenden. Sie haben also einen einzigen Sprachdienst und dann wird das tslint-Plugin zusammen mit Ihrem Plugin diesen Proxy übernehmen.

Übrigens, was Sie hier zu tun versuchen, sollte definitiv mit einem einfachen Sprachdienst-Plugin möglich sein, denn das ist es, was hier getan wird.

Wie auch immer, lasst uns versuchen, das Gespräch hier beim Thema zu halten und nur über benutzerdefinierte Transformatoren als Teil des Builds mit tsc statt Editor-Code-Änderungen/Sprachdienst-Zeug. Die meisten Leute suchen nach einer Lösung, um eine Transformation über ein gesamtes Projekt hinweg durchzuführen, und dies innerhalb des Editors zu tun, ist keine praktikable Lösung (insbesondere, da eine Transformation an diesem Punkt den Zweck ihrer Verwendung zunichte macht). Was hier implementiert werden soll, sollte idealerweise nichts mit Editor/tsserver oder Sprachdienst zu tun haben.

vielen Dank für den wertvollen Input, ich werde es berücksichtigen

Ich stimme Ihnen nicht zu, das Gespräch nur über benutzerdefinierte Transformatoren als Teil des Builds mit tsc zu führen , da

  • Die ursprüngliche schriftliche Anfrage ist nicht genau, in welcher Form die Transformationen geliefert werden sollen, sie besagt nur, dass dies nicht erforderlich sein sollte
    > Duplizieren Sie die gesamte tsc-Befehlszeile, nur um einen einzelnen Transformator hinzuzufügen
  • Über 2 Jahre hat diese Diskussion ziemlich viel Aufmerksamkeit von vielen Leuten auf sich gezogen, die sich anscheinend nicht so sehr darum kümmern, wie Transformatoren implementiert werden, vorausgesetzt, es gibt eine Lösung, die funktioniert und einfach zu bedienen ist
  • Außerdem hat das tslint-Team beim Aufbau der Infrastruktur für Plugins gute Arbeit geleistet. Es ist Zeitverschwendung, sie nicht zu verwenden, vorausgesetzt, es ist de facto die einzige offiziell anerkannte Plattform außerhalb von Typoskript, die sich mit Typoskript befasst
  • Außerdem sind wir uns alle einig, dass selbst wenn Transformatoren jemals den Weg in die Sprache finden sollten, dies in absehbarer Zeit nicht passieren wird, aber die Leute hier (mich eingeschlossen) brauchten sie wie gestern
  • Schließlich, da es nicht so viele bessere Alternativen gibt, warum sollten wir nicht zumindest das in Betracht ziehen, was wir haben?

Mein Vorschlag ist eindeutig als Problemumgehung gekennzeichnet (während das Designteam sich die Zeit nimmt, intensiver über eine geeignete Lösung nachzudenken), also warum nicht?

Wenn Sie darauf bestehen, dass wir es woanders tun sollten, melden Sie sich bitte

aber um Ihre Sorge zu adressieren

Transformation über ein gesamtes Projekt hinweg

tslint macht genau das mit seinem Argument --fix für cli

@zpdDG4gta8XKpMCd --fix aktualisiert den vorhandenen TypeScript-Code. Bei diesem Problem geht es darum, Transformationen während der Ausgabe durchzuführen (damit die Änderungen nur in den endgültigen JavaScript-Dateien landen). Siehe die PR (#13940) der referenzierten Ausgabe:

Seit #13764 gelandet ist, ist es einfach, benutzerdefinierte Transformatoren zu schreiben. Wenn ich die API jedoch richtig verstehe, muss die gesamte tsc-Befehlszeile dupliziert werden, nur um einen einzelnen Transformator hinzuzufügen. Dies führt zu Inkompatibilitäten, da diese, je nach Schreibschrift, Anwendungen nicht die gleichen Features wie das tsc-Kommandozeilentool unterstützen.

Mit anderen Worten, dieses Problem brachte CustomTransformers (klicken Sie auf diesen Link und sehen Sie, wo er in der API verwendet wird), aber um sie zu verwenden, muss tsc irgendwie dupliziert oder umschlossen werden, und das ist was ttypescript tut es. Der zweite Absatz spricht dann darüber, wie gut dies wäre, weil es sich gut in vorhandene Build-Tools integrieren würde (da die Verwendung der benutzerdefinierten Transformatoren von tsc gehandhabt würde und nicht von verschiedenen Build-Tools, die dies auf unterschiedliche Weise tun würden).

Ich denke, es wäre produktiver, ein neues Problem mit Ihren Bedenken zu Codekorrekturen zu eröffnen oder eine einfachere Möglichkeit zum Generieren von TypeScript-Code innerhalb von TypeScript-Code zu suchen. Ich bin mir nicht sicher, was genau diese Bedenken sind, da ich denke, dass vieles davon heute schon möglich ist, aber was Sie diskutiert haben, ist, wie man Code-Korrekturen/Aktionen durchführt, was für mich ein nicht verwandtes Thema zu sein scheint.

Ich denke, die Hauptfragen, die in diesem Thread beantwortet werden müssen, sind die, die Daniel besprochen hat – „vielleicht gibt es etwas Breiteres als nur Vor- und Nachtransformatoren“ – und wie die Lösung aussehen würde, um diesen Teil des Builds zu erstellen.

du bist vage

Ich bin eine Person, die einfache Dinge versteht und schätzt

mein problem ist, dass ich es mit einem projekt mit über 3500 dateien zu tun habe, von denen 15% nicht von hand geschrieben und gewartet werden müssen und ungefähr 5% ähnliches zeug noch dazu kommen

Gleichzeitig weiß ich, dass es eine API gibt, die das für mich erledigen kann, aber sie ist so unausgereift, dass ich nie rechtfertigen kann, wie viel Zeit ich damit verbringen muss, um sie fertig zu bekommen

Als ich hierher kam, dachte ich, dies sei der richtige Ort, um darüber zu sprechen, und es stellte sich heraus, dass es eine schnelle und einfache Lösung geben könnte

Pech gehabt, einige Leute, die hierher gekommen sind, um einige viel feinere Dinge zu besprechen

okay, hervorragend!

und nein, ich werde keine neue ausgabe eröffnen, nur um den leuten noch einmal zu zeigen, wie tslint eines der größten probleme lösen kann, ich habe meinen job gemacht, ich bin fertig

Es wäre schön, konfigurierbare Transformationen aus der Box zu haben. Ich versuche, ein Problem der In-Code-Zeichenfolge l10n und i18n anzugehen. Ich kann Tools wie tslint mit einer benutzerdefinierten Regel zum Extrahieren nutzen, aber meine Optionen zum Transformieren des Codes sind begrenzt, es sei denn, ich verwende etwas wie ttypescript , aber das ist problematisch, weil ich die App bin arbeite an einer nicht ausgeworfenen Winkel-App. Es zwingt mich nur, Schicht für Schicht von Build-Tools hinzuzufügen. Mit dem Tempo der Entwicklung wird der ganze Stack wirklich prekär.

Wir entwickeln derzeit ein Framework und verwenden derzeit ttypescript , um zur Laufzeit auf Informationen auf Typebene zuzugreifen. Es wäre schön, die Option plugins irgendwann im offiziellen Compiler zu haben 😄

Ich bin gerade im Urlaub, werde aber nächste Woche mal schauen, wenn ich zurück bin

Am Sonntag, 21. Juli 2019 um 17:54 Uhr Giorgio Boa [email protected]
schrieb:

@longlho https://github.com/longlho Du hast eine Menge toller Ast erstellt
Transformatoren, ich brauche bitte deine Hilfe 👍
Ich würde wirklich gerne Decorator-Metadaten vor der Angular-Kopilierung ändern.
Mein Ziel ist es, diesen Knoten zu ändern
Component({ selector: 'standard' ... }) in Component({ selector: 'custom'
... })
Ich habe ein Github-Repo zum Testen erstellt
https://github.com/gioboa/ng-ts-transformer . Ich denke, es ist möglich, aber
ohne Dokumentation brauche ich etwas Hilfe. 🙏 Danke.


Sie erhalten dies, weil Sie erwähnt wurden.
Antworten Sie direkt auf diese E-Mail und zeigen Sie sie auf GitHub an
https://github.com/microsoft/TypeScript/issues/14419?email_source=notifications&email_token=AABQM335QEEDNVT4NUICJQDQASBDXA5CNFSM4DCFER5KYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD2OGIWQ#issuecomment-51386,566
oder den Thread stumm schalten
https://github.com/notifications/unsubscribe-auth/AABQM33S5IYXB5HOZTRVVX3QASBDXANCNFSM4DCFER5A
.

Ich habe dazu beigetragen, eine Bibliothek zu erstellen, um echte Mocks von Schnittstellen ohne Proxy zu erstellen. Ich empfehle vorerst die Verwendung von ttypescript, aber es wäre schön, eine Möglichkeit zur Integration mit typescript zu haben

Ich würde wirklich gerne sehen, dass diese Funktion kommt. Ich bin mir ziemlich sicher, dass dies das einzige ist, was zwischen Typescript und einigen der größten Innovationen steht, zu denen es führen kann.

Typoskript ist ein enormer Beitrag zur Frontend-Entwicklung, aber es bremst auch weitere Innovationen…
Brechen Sie nicht die Semantik. Kein Plugin-ATM kann die Semantik brechen; und es sind überhaupt keine Plugins erlaubt :man_shrugging: Warum?
Es gibt wirklich gute Plugins, aber. Jedes Plugin muss (Schlüssel-)Wort-Tokenisierung und AST-Instation berücksichtigen)… , wirklich schwieriger Weg, etwas im Inneren zu tun.
Es ist nicht so schwer. Es ist nicht einfach, aber babel project zeigt, dass es möglich ist.
Tatsächlich ist es für babel fast trivial , neue semantische oder sogar syntaktische Phrasen einzuführen.

Ich erwarte von Typoskript nicht, dass es Semantik zulässt. (Außerdem erwarte ich natürlich keine Syntaxänderungen!)
Was ich mir vom Compiler wünsche, ist in einigen Fällen eine Verschiebung, wie (möglicherweise nur Typ) preeval.
Zum Beispiel, wenn ich eine Take-Funktion habe, wie route oder message oder so, kann der Compiler vorab bewerten und (oh, bitte, in Phase eins) die Korrektheit überprüfen.

Wenn Sie meinen vorherigen Absatz seltsam lesen. Was ist tsx und alle React-Güte?

Kein React, kein Flow, überhaupt kein Typoskript, fast nicht auf den ersten Blick.

Bitte. Ich verstehe gut, wenn ich all dies sorgfältig betrachte; aber wie wir von IE5.5+ lernen; Blockieren ist kein Weg nach vorn.

Wenn etwas verbessert werden muss, ist es immer noch die Layout-Engine. D.Knuth war vor 50 Jahren derjenige, der alle fehlenden Teile entwarf. Warum haben wir das heute nicht?? :-)
Bitte sagen Sie den Leuten, dass sie CSS in der JS-Bösartigkeit stoppen sollen.

Bitte. Open TS für semantische Intelligenz ; ähnliche Funktion mit statischer Zeichenfolgeneingabe, die Typhinweis für den Rest liefert; Analysieren Sie die tatsächliche konstante Eingabezeichenfolge…
Ein kleines Beispiel:

  • GraphQL-Aufruf-Rückgabeform
  • Intl-Eingangsform
  • …viel mehr_
    Bitte. Keine semantischen Änderungen erforderlich. Alles wird wie gewünscht funktionieren. Etwas mehr kann zur Bauzeit überprüft werden. Das war's Leute! :Hase:

stoßen

Ich experimentiere mit dem Schreiben von TS-Transformationen zur Optimierung des Imports core-js - automatisches Polyfilling für Zielumgebungen wie @babel/preset-env und @babel/runtime , aber ohne babel . Es könnte einem großen Teil der TS-Entwickler ernsthaft helfen. Aber ohne die Unterstützung benutzerdefinierter Transformationen aus der Box ohne zusätzliche Tools wie ttypescript wird die Möglichkeit, diese Transformationen zu verwenden, stark eingeschränkt sein, daher bin ich mir nicht sicher, ob es Sinn macht.

Ich habe mit einer solchen Idee experimentiert - https://github.com/webschik/typescript-polyfills-generator.
Ich denke, dass die Transformers API eine Möglichkeit eröffnen wird, babel aus der Entwicklungskette zu streichen. Ich denke, viele Entwickler wollen sie nicht beide verwenden, aber sie brauchen immer noch Plugins wie @babel/preset-env .

Aufgrund dieser Einschränkung haben wir derzeit unser eigenes benutzerdefiniertes Compiler-Skript (unter Verwendung der TypeScript-Compiler-API) eingeführt. Wir haben uns kurz ttypescript angeschaut , aber der Appetit, weg vom einfachen TypeScript-Compiler zu einer Erweiterung des TypeScript-Compilers zu wechseln, ist einfach nicht da.

Es wäre fantastisch, wenn benutzerdefinierte Transformer in tsconfig.json unterstützt würden. Es ist umständlich, ein Skript zu schreiben, das einfach tsconfig parst, Transformer deklariert und dann den Compiler ausführt; oder, schlimmer noch, um tatsächlich zu versuchen, grundlegende Funktionen des Compilers, wie das Überwachen von Dateien, in einem benutzerdefinierten Skript neu zu implementieren.

Andere Leute haben diese Meinung wiederholt, aber die einfache Integration benutzerdefinierter Transformatoren in den Compiler würde das TypeScript-Entwicklungsteam erheblich entlasten und Innovationen und zusätzliche Vorwärtsbewegungen mit dieser Sprache von der Community ermöglichen.

Ein Beispiel für ein sehr erfolgreiches Plugin-Ökosystem ist die Plugin-Community des Serverless Framework. Das Entwicklungsteam kann mit der Nachfrage nach Funktionsentwicklung nicht Schritt halten, und Plugins bieten eine großartige Möglichkeit, die Integration neuer (möglicherweise experimenteller) Funktionen zu ermöglichen, ohne dass PRs geöffnet oder das Kernprodukt mit Funktionen verwässert werden müssen, die möglicherweise oder möglicherweise erforderlich sind bieten der breiteren Benutzerbasis keinen Mehrwert.

Ich baue eine Bibliothek und habe Dekorateure darin, die großartig für mich arbeiten und auf die ich mich verlassen kann. Ich habe vor einiger Zeit festgestellt, dass Dekorateure meine Bibliothek nicht baumerschütternd machen. Nachdem ich mich damit befasst hatte, kam ich zu dem Schluss, dass Transformer mir helfen könnten, diese Dekorateure bei der Kompilierung in baumerschütterbaren Code umzuwandeln. Leider kann ich sie nicht in meiner Pipeline definieren. Ich hoffe, Sie kommen bald zu diesem Thema, wollte nur meine 2 Cent auf einen Anwendungsfall fallen lassen, bei dem es sehr hilfreich wäre.

Um TypeScript dazu zu bringen, benutzerdefinierte Transformatoren ohne Wrapper-Programme und komplizierte Anweisungen zu unterstützen, habe ich ein Tool namens ts-patch ( npm github ) geschrieben.

Installieren Sie einfach ts-patch (global oder lokal) und führen Sie ts-patch install aus, um Typoskript zu patchen. Sie können auch das Typoskript-Installationsverzeichnis angeben und/oder Persistenz aktivieren, wodurch der Patch beibehalten wird, wenn TS aktualisiert oder neu installiert wird. (Einzelheiten: ts-patch /? )

Die Patch-Logik basiert hauptsächlich auf ttypescript. (Großen Dank an die großartige Arbeit von cevek!) Es ist so geschrieben, dass es einfach zum npm-Paketinstallationsprozess hinzugefügt werden kann. Es ist auch einfach zu entpatchen.

Um es klar zu sagen, dies patcht direkt relevante Dateien in Typoskript selbst und ist kein Wrapper. Führen Sie einfach den Patch nach der Installation der Abhängigkeit aus, und Typoskript ist bereit für den Transformer.

Hoffe das hilft einigen Leuten!

Um TypeScript dazu zu bringen, benutzerdefinierte Transformatoren ohne Wrapper-Programme und komplizierte Anweisungen zu unterstützen, habe ich ein Tool namens ts-patch ( npm github ) geschrieben.

Installieren Sie einfach ts-patch (global oder lokal) und führen Sie ts-patch install aus, um Typoskript zu patchen. Sie können auch das Typoskript-Installationsverzeichnis angeben und/oder Persistenz aktivieren, wodurch der Patch beibehalten wird, wenn TS aktualisiert oder neu installiert wird. (Einzelheiten: ts-patch /? )

Die Patch-Logik basiert hauptsächlich auf ttypescript. (Großen Dank an die großartige Arbeit von cevek!) Es ist so geschrieben, dass es einfach zum npm-Paketinstallationsprozess hinzugefügt werden kann. Es ist auch einfach zu entpatchen.

Um es klar zu sagen, dies patcht direkt relevante Dateien in Typoskript selbst und ist kein Wrapper. Führen Sie einfach den Patch nach der Installation der Abhängigkeit aus, und Typoskript ist bereit für den Transformer.

Hoffe das hilft einigen Leuten!

Könnte dies als PR angehoben werden, um die richtige Unterstützung hinzuzufügen / zu diskutieren? :)

Hey. Für das, was es wert ist, gibt es einen Bundler namens Fuse-Box, der es sehr einfach macht, benutzerdefinierte Transformatoren hinzuzufügen. Seine 4.0-Version kommt bald ... also ist es an einer Stelle dazwischen. Aber insgesamt gefällt mir der Bundler sehr gut. Vielleicht kann es dir auch helfen.

https://github.com/fuse-box/fuse-box/blob/master/docs/plugins/pluginCustomTransform.md

Könnte dies als PR angehoben werden, um die richtige Unterstützung hinzuzufügen / zu diskutieren? :)

Das TS-Team hat zum Ausdruck gebracht, dass es dies nicht als natives Feature bereitstellen möchte. Ihre Gründe für die Entscheidung machen Sinn!

Die gute Nachricht ist, dass sich ts-patch, da TS Open Source und bereits modular kompiliert ist, sehr ähnlich verhält, als wäre es eingebaut. Es ist also nicht wie ein fehlerhafter, rückentwickelter Bytecode-Patch.

Wenn Sie vom Support besorgt sind, dass es gewartet wird, plane ich, es auf dem neuesten Stand zu halten und für alle zukünftigen Versionen von TS zu verwenden! Ein Großteil meiner kommerziellen Infrastruktur hängt bereits davon ab.

Als Randnotiz werde ich bald eine neue Version veröffentlichen, die es ermöglicht, mehrere Plugins mit unterschiedlichen Einstiegspunkten in ein einziges Paket zu packen, sowie einige andere Optimierungen, um es zu verbessern und die Verwendung zu vereinfachen.

Nachdem ich ein Plugin geschrieben habe, kann ich verstehen, warum das ts-Team zögert - der Stromwandler ist ein Post-Compile-Schritt. Sie stoßen auf unangenehme Probleme, wenn Sie etwas Kompliziertes tun und anfangen, neue Inhalte hinzuzufügen, die ursprünglich nicht gebunden waren. So wie es aussieht, funktioniert ts-node --compiler ttypescript foo.ts einwandfrei. Ich möchte lieber, dass sich das ts-Team mit Transformer-Plugins in verschiedenen Kompilierungsschritten befasst ... oder einen Neubindungsschritt zulässt.

Der Stromtransformator ist ein Post-Compile-Schritt. Sie stoßen auf unangenehme Probleme, wenn Sie etwas Kompliziertes tun und anfangen, neue Inhalte hinzuzufügen, die ursprünglich nicht gebunden waren.

Transformers können entweder vor oder nach der TSC-Kompilierung ausgeführt werden. Es hört sich so an, als ob Sie sich darauf beziehen, dass der Checker nach dem Ändern von Knoten nicht aktualisiert wird. Dies kann tatsächlich umgangen werden, die Funktionalität wurde einfach nicht dafür entwickelt. Wenn Sie ts.transform() aufrufen, wird keine vollständige Programminstanz erstellt, mit der Sie arbeiten können. Wenn Sie also mit dem Checker arbeiten möchten, müssen Sie eine erstellen. Mit CompilerHost können Sie es mit den geänderten Dateien neu laden, nachdem Sie den AST geändert haben.

Ich habe mich noch nicht allzu weit damit befasst, aber es sieht so aus, als wäre es auch möglich, die „Überwachungs“-Funktionalität zu verwenden, um zu vermeiden, dass jedes Mal die gesamte Programminstanz neu erstellt werden muss. Einfach gesagt, es stellt sich heraus, dass es eigentlich nicht _zu_ schwierig ist, ein vollständigeres Plugin-System zu haben, aber transform fehlt einfach die Unterstützung in seinem bereitgestellten Kontext.

@nonara Ich habe Transformationen mit ttypescript und ts-loader` verwendet, beide haben vollständige Programmeintrittspunkte. Mein Problem ist, dass, wenn Sie eine neue import-Anweisung hinzufügen, ihr "etwas" fehlt und diese neuen Anweisungen aus der endgültigen Ausgabe entfernt werden. @weswigham sagt, dass es daran liegt, dass transform ein Post-Binding-Schritt ist . Die Lösung besteht anscheinend darin, ein völlig neues Programm für die Datei zu erstellen - aber das scheint nur Kopfschmerzen zu sein, wenn Sie mit Dingen wie dem ts-Loader zu tun haben (insbesondere wenn er sich im reinen Transformationsmodus befindet und die Webpack- / Bundler-Datei vollständig verbirgt - Resolver Am Ende habe ich den Import verworfen und nur den benötigten Code eingefügt .

@MeirionHughes Ah, ok. In diesem Fall haben Sie ja eine Programminstanz. ttypescript funktioniert durch Hooken von createProgram, um die Ausgabemethode des resultierenden program so zu patchen, dass sie die Transformer enthält.

  • ts.emitFiles ruft während des Vorgangs ts.transformNodes auf.
  • ts.transformNodes kann mit oder ohne Programminstanz aufgerufen werden. Das direkte Aufrufen ts.transform() funktioniert ohne eins.

Wenn ich es richtig verstehe, scheint Ihr Problem auch damit zusammenzuhängen, dass die Typen und Symbole bereits durchlaufen wurden und nach der AST-Transformation nicht aktualisiert werden.

Hallo zusammen, ich habe ein Transformer-Handbuch geschrieben, um alle Informationen über Transformatoren zusammenzustellen und den Einstieg zu erleichtern.

https://github.com/madou/ts-transformer-handbook/blob/master/translations/en/transformer-handbook.md

Würde mich über ein paar Augen freuen, wenn Sie eine Sekunde Zeit haben 👍

@madou Ich habe auch viele Beiträge zu TS-Transformatoren geschrieben https://levelup.gitconnected.com/writing-typescript-custom-ast-transformer-part-1-7585d6916819

Wie ist der Stand diesbezüglich?

Ich liebe Typoskript sehr, aber es fühlt sich besonders klobig an, wenn Sie anfangen, zwischen statischen Typen und Laufzeit-JS zu interagieren. Es gibt zahlreiche von der Community geschriebene Plugins, um dies zu verbessern, z. B. https://github.com/dsherret/ts-nameof , https://github.com/kimamula/ts-transformer-keys - jedoch ohne erstklassige Plugin-Unterstützung es fühlt sich wie eine riskante technische Entscheidung an, sie in ein Projekt einzubeziehen. Die native Aktivierung von Plugins würde es der Community ermöglichen, mit potenziellen zukünftigen Typoskript-Funktionen herumzuspielen, bevor sie in die Kernbibliothek aufgenommen werden müssen.

Ich denke, das TypeScript-Team sollte seine Argumentation überdenken. Das Plugin-Ökosystem ist ein bewährtes Mittel, um die Sprache voranzubringen und Experimente zu ermöglichen (und zu ermutigen) (siehe Haskell mit seinen Pragmas).

Einige dieser Experimente werden wild und verrückt sein, und einige werden sich schließlich stabilisieren und alltäglich werden. Es ist immer gut, die Möglichkeit zu bieten, Sprachfunktionen im Benutzerbereich zu implementieren.

Im Allgemeinen sieht die Position des TypeScript-Teams unnötig starr aus.

Es gibt auch Transformationen, die die Sprache nicht ändern, aber zusätzliche Informationen zum einfacheren Debuggen bereitstellen.

Beispielsweise ist die babel-plugin-transform-react-jsx-source Teil der standardmäßigen React-Transpiling-Voreinstellung ( @babel/preset-react ).
Es verwandelt sich

<sometag />

Hinein

<sometag __source={ { fileName: 'this/file.js', lineNumber: 10 } } />

Diese Informationen ermöglichen es react , während der Entwicklung bessere Stack-Traces für Fehler bereitzustellen.

Für Typoskript gibt es keine Standardmethode, um dasselbe zu erreichen, obwohl es eine Open-Source-Transformation gibt: https://github.com/dropbox/ts-transform-react-jsx-source

Ich verstehe, dass @mhegazy zweimal erwähnt hat, dass das TS-Team nicht vorhat, „Plugins“ als Teil von tsconfig einzuschließen. Was steckt dahinter?

Wären Sie offen für eine PR? Die Art und Weise, wie ttypescript die Transformatoren über tsconfig handhabt, ist ziemlich nett.

Anwendungsfälle:

1) Generieren von Schnittstellentypen zu Schemas, damit sie zur Laufzeit überprüft werden können.
2) Importieren von JSON mit Zeichenfolgen als Literale, damit Typoskript nicht barf, wenn es einem Typ mit diskriminierten Vereinigungen zugewiesen wird.
3) Importieren von CSS/YAML und anderen Objekten wie Syntax
4) Erstellen von graphql-Abfragen, die dynamisch die richtigen Typen erstellen
5) Kompilieren von JSX zu HTML-Strings, damit sie innerHTML injiziert werden können
5) Umschreiben absoluter Importe in relative Importe basierend auf tsconfig-Pfaden.

Die Liste geht weiter und weiter. Die Plugin-API ist nett. Danke, dass du es gelandet hast. Dass „Plugins“ Teil von „tsconfig“ ist, macht tsc wirklich mächtig. Gibt es etwas Großes, das wir vermissen?

Sie können auch viele Leistungsoptimierungen vornehmen. Ich habe https://github.com/atlassian-labs/compiled-css-in-js mit Typoskript-Transformatoren geschrieben 🤙 wäre cool, wenn die Verbraucher nicht durch die Reifen springen müssten, um es zu benutzen.

Sehr geehrtes Typescript-Team, bitte hören Sie auf, sich hier rumzuschleppen <_<

Wie ist der Stand diesbezüglich?

Status?

Freunde was für Neuigkeiten?

Das Typoskript-Team hat sich gegen diese Idee entschieden - wenn Sie Flexibilität oder bessere Entwicklungswerkzeuge benötigen, ist die Verwendung von Typoskript ohne Hacks keine Option - entscheiden Sie sich stattdessen für babel und verwenden Sie Typoskript nur für die Typprüfung

Das Typoskript-Team hat sich gegen diese Idee entschieden - wenn Sie Flexibilität oder bessere Entwicklungswerkzeuge benötigen, ist die Verwendung von Typoskript ohne Hacks keine Option - entscheiden Sie sich stattdessen für babel und verwenden Sie Typoskript nur für die Typprüfung

Aber was ist, wenn ich ein paar Hacks für die Typprüfung haben möchte? Ich schreibe einen kleinen Transformator, der etwas Magie macht:

type Human = {
    name: string,
    age: number
}

const isValid = check<Human>({ name: 'Carl', age: 16 }) // => true
const isValid = check<Human>({ name: 'Carl' }) // => false

Funktion check in spezifische Typschutzfunktion umgewandelt! Wie kann ich es mit Babel machen? Derzeit sollte ich ttypescript verwenden ...

Das Typoskript-Team hat sich gegen diese Idee entschieden - wenn Sie Flexibilität oder bessere Entwicklungswerkzeuge benötigen, ist die Verwendung von Typoskript ohne Hacks keine Option - entscheiden Sie sich stattdessen für babel und verwenden Sie Typoskript nur für die Typprüfung

Es gibt tatsächlich einige Gespräche darüber, dass dies in Zukunft unterstützt wird. Das heißt, es wird wirklich bereits unterstützt. Die TypeScript-Compiler-API unterstützt Transformer, und es ist _wirklich_ einfach, einen benutzerdefinierten Compiler zu schreiben, der Transformer in nur wenigen Codezeilen verwendet.

Aber um es einfacher zu machen, können Sie ttypescript oder ts-patch verwenden.

Diese Bibliotheken sind nicht wirklich "Hacks" in dem Sinne, dass sie den Compiler nicht erweitern, um Transformer-Fähigkeiten hinzuzufügen. Stattdessen stellen sie einfach die vorhandene Funktionalität der Compiler-API für tsc bereit und machen sie über tsconfig nutzbar.

@ilya-buligin Wenn ich Ihren Anwendungsfall richtig verstehe, können Sie eine Umgebungskonstante deklarieren

declare const check: <T>(value: unknown) => value is T;

const isValid = check<Human>({ name: 'Carl', age: 16 }) // => true

Typescript kompiliert den Code basierend auf der Typdefinition von check und Sie ersetzen ihn dann durch einen generierten Code, der Babel verwendet.

@just-boris, wie kann ich in Babel auf den generischen Typ <T> zugreifen?

Dieser Thread wird ziemlich repetitiv und off-topic. @RyanCavanaugh Vielleicht sollte dieser Thread gesperrt werden, bis Sie Neuigkeiten zu diesem Thema haben.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen

Verwandte Themen

kyasbal-1994 picture kyasbal-1994  ·  3Kommentare

Roam-Cooper picture Roam-Cooper  ·  3Kommentare

fwanicka picture fwanicka  ·  3Kommentare

manekinekko picture manekinekko  ·  3Kommentare

blendsdk picture blendsdk  ·  3Kommentare