Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(generator): add support for arrays #556

Merged
merged 2 commits into from
Dec 21, 2023
Merged

Conversation

Wykerd
Copy link
Collaborator

@Wykerd Wykerd commented Dec 11, 2023

Adds better inference support for arrays to the YTNode generator.

Before:

class Test extends YTNode {
  static type = 'Test';

  array: {
    0: {
      key1: string
    },
    1: {
      key1: string,
      key2: boolean
    }
  };

  constructor(data: RawNode) {
    super();
    this.array = {
      0: {
        key1: data.array.0.key1
      },
      1: {
        key1: data.array.1.key1,
        key2: data.array.1.key2
      }
    };
  }
}

After:

class Test extends YTNode {
  static type = 'Test';

  array: {
    key1: string,
    key2?: boolean
  }[];

  constructor(data: RawNode) {
    super();
    this.array = data.array.map((item: any) => ({
      key1: item.key1,
      key2: Reflect.has(item, 'key2') ? item.key2 : undefined
    }));
  }
}

@Wykerd
Copy link
Collaborator Author

Wykerd commented Dec 11, 2023

Initial tests with this script seem to be working (see below). Just need to test that render lists still work as expected.

import { camelToSnake, generateRuntimeClass, generateTypescriptClass } from './parser/generator.js';

const TestItem = generateRuntimeClass('TestItem', {
    contents: []
}, (err) => {
    if (err.error_type === 'class_not_found') {
        console.warn(
            `Introspected and JIT generated this class in the meantime:\n${generateTypescriptClass(err.classname, err.key_info)}`
        );
    }
    if (err.error_type === 'class_changed') {
        console.warn(
            `The following keys where altered: ${err.changed_keys.map(([ key ]) => camelToSnake(key)).join(', ')}\n` +
            `The class has changed to:\n${generateTypescriptClass(err.classname, err.key_info)}`
        )
    }
});

console.log(new TestItem({
    contents: [
        {
            test: 'test1',
            item: 1
        },
        {
            test: 'test2',
            item: 2,
            error_reasons: [
                {
                    code: 123,
                    message: 'test'
                }
            ]
        }
    ]
}));

console.log(new TestItem({
    contents: [
        {
            test: 'test3',
            item: 3,
            error_reasons: [
                {
                    code: 500,
                    message: 'fatal',
                    fatal: true
                }
            ]
        }
    ]
}));

Producing the following TypeScript classes:

Introspected and JIT generated this class in the meantime:
class TestItem extends YTNode {
  static type = 'TestItem';

  contents: never[];

  constructor(data: RawNode) {
    super();
    this.contents = data.contents;
  }
}

The following keys where altered: contents
The class has changed to:
class TestItem extends YTNode {
  static type = 'TestItem';

  contents: {
    test: string,
    item: number,
    error_reasons?: {
      code: number,
      message: string
    }[]
  }[];

  constructor(data: RawNode) {
    super();
    this.contents = data.contents.map((item: any) => ({
      test: item.test,
      item: item.item,
      error_reasons: Reflect.has(item, 'error_reasons') ? item.error_reasons.map((item: any) => ({
        code: item.code,
        message: item.message
      })) : undefined
    }));
  }
}

TestItem {
  type: 'TestItem',
  contents: [
    { test: 'test1', item: 1, error_reasons: undefined },
    { test: 'test2', item: 2, error_reasons: [Array] }
  ]
}
The following keys where altered: contents
The class has changed to:
class TestItem extends YTNode {
  static type = 'TestItem';

  contents: {
    test: string,
    item: number,
    error_reasons?: {
      code: number,
      message: string,
      fatal?: boolean
    }[]
  }[];

  constructor(data: RawNode) {
    super();
    this.contents = data.contents.map((item: any) => ({
      test: item.test,
      item: item.item,
      error_reasons: Reflect.has(item, 'error_reasons') ? item.error_reasons.map((item: any) => ({
        code: item.code,
        message: item.message,
        fatal: Reflect.has(item, 'fatal') ? item.fatal : undefined
      })) : undefined
    }));
  }
}

TestItem {
  type: 'TestItem',
  contents: [ { test: 'test3', item: 3, error_reasons: [Array] } ]
}

Add Parser#parse overload to support non array validTypes.

Fixes issue in generator generating invalid Parser#parse calls
introduced in #551.
@Wykerd
Copy link
Collaborator Author

Wykerd commented Dec 11, 2023

Tested with ClipCloud. Seems to still generate valid runtime and TS classes for renderer lists.

class ChipCloud extends YTNode {
  static type = 'ChipCloud';

  chips: ObservedArray<YTNodes.ChipCloudChip> | null;
  horizontal_scrollable: boolean;

  constructor(data: RawNode) {
    super();
    this.chips = Parser.parse(data.chips, true, YTNodes.ChipCloudChip);
    this.horizontal_scrollable = data.horizontalScrollable;
  }
}

@Wykerd Wykerd marked this pull request as ready for review December 11, 2023 21:07
@LuanRT LuanRT merged commit e4f2a00 into main Dec 21, 2023
4 checks passed
@Wykerd Wykerd deleted the Wykerd-generator-arrays branch December 22, 2023 00:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants