From 15b815e9031aad1842ee6f4295eecff5bd3a82e3 Mon Sep 17 00:00:00 2001 From: ymayarajan3 Date: Thu, 23 May 2024 19:02:11 -0400 Subject: [PATCH] instance reporter --- .../common/extension/decorators/newBlocks.ts | 143 ++++++++++-------- extensions/src/simple_example/index.ts | 8 +- 2 files changed, 88 insertions(+), 63 deletions(-) diff --git a/extensions/src/common/extension/decorators/newBlocks.ts b/extensions/src/common/extension/decorators/newBlocks.ts index 3eebdd40e..c55750a92 100644 --- a/extensions/src/common/extension/decorators/newBlocks.ts +++ b/extensions/src/common/extension/decorators/newBlocks.ts @@ -1,23 +1,27 @@ import { getImplementationName } from "../mixins/base/scratchInfo/index"; -import { BlockMetadata } from "$common/types"; +import { BlockMetadata, Argument, ScratchArgument, ToArguments } from "$common/types"; import { blockBundleEvent } from "$common/extension/decorators/blocks"; import { BlockType } from "$common/types/enums"; import { ExtensionInstance } from ".."; -import type BlockUtility from "$scratch-vm/engine/block-utility"; -import { isFunction, isString, tryCreateBundleTimeEvent } from "$common/utils"; +import type BlockUtilityWithID from "$scratch-vm/engine/block-utility"; +import { isFunction, isString } from "$common/utils"; import { extractArgs } from "../mixins/base/scratchInfo/args"; +import { TypedMethodDecorator } from "."; -type BlockFunctionMetadata = { - methodName: string, - scratchType: string, - args: string[], - returns: string, - } +type TRemoveUtil = T extends [...infer R extends any[], BlockUtilityWithID] ? R : T; +//export const blockBundleEvent = tryCreateBundleTimeEvent("blocks"); +const extractTaggedTemplateLiteral = (funcString) => { + // Define a regular expression pattern to match the tagged template literal + const pattern = /`([^`]*)`/; -type TRemoveUtil = any[] extends [...infer R extends any[], BlockUtility] ? R : any[] -//export const blockBundleEvent = tryCreateBundleTimeEvent("blocks"); + // Match the tagged template literal in the string + const match = funcString.match(pattern); + + // Return the tagged template literal component + return match ? match[1] : null; +}; export function makeDecorator(type: T): TemplateEngine["execute"] { @@ -29,26 +33,46 @@ export function makeDecorator(type: T): TemplateEn //context is ClassMethodDecoratorContext const opcode = target.name; const internalFuncName = getImplementationName(opcode); - - const argList: any[] = args; - + let argList: any[] = args; const blockType = (type === "reporter") ? BlockType.Reporter : BlockType.Command; - const textFunction = (...args) => { - // Concatenate template strings and arguments dynamically - const strings = Array.isArray(builderOrStrings) ? builderOrStrings : [builderOrStrings]; - let result = ''; - strings.forEach((str, index) => { - result += str; - if (index < args.length) { - result += args[index]; - } - }); - return result; - }; - type Fn = (this: ExtensionInstance, value: any, util: BlockUtility) => void; + let textFunction; + if (typeof builderOrStrings == "function") { + const taggedTemplateLiteral = extractTaggedTemplateLiteral(builderOrStrings.toString()); + const tagFunction = (strings1, ...values) => { + // Process the tagged template literal with the provided strings and values + argList = values; + textFunction = (...values: any[]) => { + let result = ''; + strings1.forEach((str, index) => { + result += str; + if (index < values.length) { + result += values[index]; + } + }); + return result; + }; + return ""; + + }; + tagFunction`Invoke function`; + const taggedTemplate = eval("tagFunction`" + taggedTemplateLiteral + "`"); + + } else { + textFunction = (...args: any[]) => { + const strings = Array.isArray(builderOrStrings) ? builderOrStrings : [builderOrStrings]; + let result = ''; + strings.forEach((str, index) => { + result += str; + if (index < args.length) { + result += args[index]; + } + }); + return result; + }; + } + type Fn = (this: ExtensionInstance, value: any, util: BlockUtilityWithID) => void; const blockInfo = { type: blockType, text: textFunction, args: argList }; context.addInitializer(function () { this.pushBlock(opcode, blockInfo as BlockMetadata, target) }); - const isProbableAtBundleTime = !isFunction(blockInfo); if (isProbableAtBundleTime) { const { type } = blockInfo; @@ -87,12 +111,12 @@ export function makeDecorator(type: T): TemplateEn namespace Utility { - export type TypedMethodDecorator< - This, - Args extends any[], //args that the decorator accepts - Return, //what the decorator returns - Fn extends (...args: Args) => Return // function signature that matches the method being decorated. - > = (target: Fn, context: ClassMethodDecoratorContext) => Fn; + // export type TypedMethodDecorator< + // This, + // Args extends any[], //args that the decorator accepts + // Return, //what the decorator returns + // Fn extends (...args: Args) => Return // function signature that matches the method being decorated. + // > = (target: Fn, context: ClassMethodDecoratorContext) => Fn; //ClassMethodDecoratorContext is actually defining the decorator function export type Method = (this: This, ...args: Args) => Return; @@ -101,39 +125,33 @@ namespace Utility { export type TaggedTemplate = (strings: TemplateStringsArray, ...args: TArgs) => TReturn; } -namespace Framework { - export class ExtensionInstance { } - export type BlockUtility = { dummy: true } - // Q: what is the purpose of this? And why do they need to be filtered out? -} - namespace Argument { export type ScratchType = "number" | "string" | "angle"; - export type ToType = - T extends "number" | "angle" ? number : - T extends "string" ? string : - never; + // export type ToType = + // T extends "number" | "angle" ? number : + // T extends "string" ? string : + // never; - export type ScratchConfig = T | { type: T, default?: ToType }; + //export type ScratchConfig = T | { type: T, default?: ToType }; - export type RemoveUtil = T extends [...infer R extends any[], Framework.BlockUtility] ? R : T; + //export type RemoveUtil = T extends [...infer R extends any[], BlockUtilityWithID] ? R : T; /** * Transform plain typescript type to it's Scratch representation (`ScratchConfig`) */ - export type FromType = - T extends number ? ScratchConfig<"number"> : - T extends string ? ScratchConfig<"string"> : - never; + // export type FromType = + // T extends number ? Argument<"number"> : + // T extends string ? Argument<"string"> : + // never; /** * Transform arguments of method into a corresponding tuple of `ScratchConfig` types. * * NOTE: The second type parameter should not be specified. */ - export type MapToScratch = RemoveUtil> = { - [k in keyof Internal]: FromType + export type MapToScratch = TRemoveUtil> = { + [k in keyof Internal]: Argument } } @@ -147,11 +165,11 @@ namespace Block { T extends "command" ? void | Promise : never; - export type Config = { - type: ScratchType, - text: string, - args: Argument.ScratchConfig[] - } + // export type Config = { + // type: ScratchType, + // text: string, + // args: Argument.ScratchConfig[] + // } //Q: what is this used for? } @@ -160,13 +178,13 @@ interface TemplateEngine { * */ execute< - const This extends Framework.ExtensionInstance, + const This extends ExtensionInstance, const Args extends any[], const Return extends Block.ToReturnType, > ( strings: TemplateStringsArray, ...args: Argument.MapToScratch - ): Utility.TypedMethodDecorator>; + ): TypedMethodDecorator>; // parameters match builderOrStrings, ...args // args are mapped // return of block function is based on report or command @@ -175,13 +193,14 @@ interface TemplateEngine { * */ execute< - const This extends Framework.ExtensionInstance, + const This extends ExtensionInstance, const Args extends any[], const Return extends Block.ToReturnType, > ( - builder: (instance: This, tag: Utility.TaggedTemplate, Block.Config>) => Block.Config - ): Utility.TypedMethodDecorator>; + builder: (instance: This, tag: Utility.TaggedTemplate, TypedMethodDecorator>>) + => TypedMethodDecorator> + ); // function takes the string of Tagged Template // parameters match builderOrStrings, ...args // return of block function is based on report or command diff --git a/extensions/src/simple_example/index.ts b/extensions/src/simple_example/index.ts index f39f62db1..3e883609d 100644 --- a/extensions/src/simple_example/index.ts +++ b/extensions/src/simple_example/index.ts @@ -18,6 +18,7 @@ const details: ExtensionMenuDisplayDetails = { export default class SimpleTypescript extends extension(details, "ui", "customSaveData", "indicators") { count: number = 0; + value: number = 4; logOptions: Menu = { items: ['1', 'two', 'three'], @@ -54,11 +55,16 @@ export default class SimpleTypescript extends extension(details, "ui", "customSa console.log(value); } - @reporter`TEST ${{type: "number", default: 3}} to ${"number"}` + @reporter`TEST ${{type: "number", defaultValue: 3}} to ${"number"}` simpleReporter(x: number, y: number) { return x + y; } + @reporter((instance, $) => $`Add ${{type: "number", defaultValue: 3}} to ${"number"}`) + reporterWithCallback(x: number, y: number) { + return x + y; + } + @block({ type: "command", args: [