winglang / wing

A programming language for the cloud ☁️ A unified programming model, combining infrastructure and runtime code into one language ⚡
https://winglang.io
Other
4.78k stars 189 forks source link

Wing Platform overrides do not work on extended classes #6093

Open hasanaburayyan opened 3 months ago

hasanaburayyan commented 3 months ago

I tried this:

when extending in non-entrypoint files

// main.w

bring "./lib.w" as lib;

let b = new lib.CustomBucket();

// lib.w

bring cloud;

pub class CustomBucket extends cloud.Bucket {}

Produces preflight code like

class CustomBucket extends (this.node.root.typeForFqn("@winglang/sdk.cloud.Bucket") ?? cloud.Bucket) {

The issue is that within this non-entrypoint preflight code, the class this.node.root happens at the top level where there is no this.

We need to somehow provide the App or PlatformManager to non entrypoint files so they can call app.node.root

This happened:

resource instantiating does not go through proper polycon hook process.

I expected this:

No response

Is there a workaround?

No response

Anything else?

No response

Wing Version

No response

Node.js Version

No response

Platform(s)

No response

Community Notes

hasanaburayyan commented 3 months ago

Opening this issue because Im going to fix half the problem in: https://github.com/winglang/wing/pull/6095, which is defined in https://github.com/winglang/wing/issues/4791 but there is a larger refactor that needs to happen

staycoolcall911 commented 3 months ago

I just wanted to point out what are the functional implications of this issue for users:

They can't both add a custom platform that overrides a specific resource factory and also extend that same resource in their project (but only in non-entrypoint files).

I'm struggling with finding an example of a real-world use case for doing both resource customizations in the same Wing project.

Chriscbr commented 3 months ago

One use case might be "I'm using the AWSCDK Wing platform for base implementations of cloud resources, and I'm extending those classes in my own Wing app"

Chriscbr commented 1 month ago

I think this bug also applies to non-entrypoint files, see the example below:

// main.w
bring "@cdktf/provider-aws" as aws;

pub class MyBucket extends aws.s3Bucket.S3Bucket {}

new MyBucket();
// my-platform.js
const aws = require("@cdktf/provider-aws");

exports.Platform = class MyPlatform {
  target = "tf-aws"
  newInstance(type, scope, id, props) {
    if (type === "@cdktf/provider-aws.s3Bucket.S3Bucket") {
      return new aws.s3Bucket.S3Bucket(scope, id, {
        ...props,
        bucketPrefix: "foo",
      })
    }
  }
}

A possible solution could be to refactor the API of Wing Platforms so instead of directly constructing instances for you, a platform returns types instead:

exports.Platform = class MyPlatform {
  target = "tf-aws";
  typeForFqn(fqn) {
    if (fqn === "@cdktf/provider-aws.s3Bucket.S3Bucket") {
      return class extends aws.s3Bucket.S3Bucket {
        constructor(scope, id, props) {
          super(scope, id, {
            ...props,
            bucketPrefix: "bar",
          })
        }
      }
    }
  }
}
hasanaburayyan commented 1 month ago

@Chriscbr yea this is the same issue. I think for sure typeForFqn needs to be implemented by the platform. Though the core of the issue is that in preflight.js files for non-entrypoint files we still have this issue:

class CustomBucket extends (this.node.root.typeForFqn("@winglang/sdk.cloud.Bucket") ?? cloud.Bucket) {

Where this.node... has no this to reference. So we need some sort of global polycon factory (which has proven challenging with cyclical dependencies) OR I think we can use that nifty little trick of changing an object's prototype in its constructor (which I have yet to try implementing)