Skip to content

Commit

Permalink
instance reporter
Browse files Browse the repository at this point in the history
  • Loading branch information
mayarajan3 committed May 23, 2024
1 parent c9e85e0 commit 15b815e
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 63 deletions.
143 changes: 81 additions & 62 deletions extensions/src/common/extension/decorators/newBlocks.ts
Original file line number Diff line number Diff line change
@@ -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 any[]> = T extends [...infer R extends any[], BlockUtilityWithID] ? R : T;
//export const blockBundleEvent = tryCreateBundleTimeEvent<BlockFunctionMetadata>("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<BlockFunctionMetadata>("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<T extends Block.ScratchType,>(type: T): TemplateEngine<T>["execute"] {

Expand All @@ -29,26 +33,46 @@ export function makeDecorator<T extends Block.ScratchType,>(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<Fn>, target) });

const isProbableAtBundleTime = !isFunction(blockInfo);
if (isProbableAtBundleTime) {
const { type } = blockInfo;
Expand Down Expand Up @@ -87,12 +111,12 @@ export function makeDecorator<T extends Block.ScratchType,>(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<This, Fn>) => 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<This, Fn>) => Fn;
//ClassMethodDecoratorContext is actually defining the decorator function

export type Method<This, Args extends any[], Return> = (this: This, ...args: Args) => Return;
Expand All @@ -101,39 +125,33 @@ namespace Utility {
export type TaggedTemplate<TArgs extends any[], TReturn> = (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 ScratchType> =
T extends "number" | "angle" ? number :
T extends "string" ? string :
never;
// export type ToType<T extends ScratchType> =
// T extends "number" | "angle" ? number :
// T extends "string" ? string :
// never;

export type ScratchConfig<T extends ScratchType = ScratchType> = T | { type: T, default?: ToType<T> };
//export type ScratchConfig<T extends ScratchType = ScratchType> = T | { type: T, default?: ToType<T> };

export type RemoveUtil<T extends any[]> = T extends [...infer R extends any[], Framework.BlockUtility] ? R : T;
//export type RemoveUtil<T extends any[]> = T extends [...infer R extends any[], BlockUtilityWithID] ? R : T;

/**
* Transform plain typescript type to it's Scratch representation (`ScratchConfig`)
*/
export type FromType<T> =
T extends number ? ScratchConfig<"number"> :
T extends string ? ScratchConfig<"string"> :
never;
// export type FromType<T> =
// 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<T extends any[], Internal extends RemoveUtil<T> = RemoveUtil<T>> = {
[k in keyof Internal]: FromType<Internal[k]>
export type MapToScratch<T extends any[], Internal extends TRemoveUtil<T> = TRemoveUtil<T>> = {
[k in keyof Internal]: Argument<Internal[k]>
}
}

Expand All @@ -147,11 +165,11 @@ namespace Block {
T extends "command" ? void | Promise<void> :
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?
}

Expand All @@ -160,13 +178,13 @@ interface TemplateEngine<TBlockType extends Block.ScratchType> {
*
*/
execute<
const This extends Framework.ExtensionInstance,
const This extends ExtensionInstance,
const Args extends any[],
const Return extends Block.ToReturnType<TBlockType>,
>
(
strings: TemplateStringsArray, ...args: Argument.MapToScratch<Args>
): Utility.TypedMethodDecorator<This, Args, Return, Utility.Method<This, Args, Return>>;
): TypedMethodDecorator<This, Args, Return, Utility.Method<This, Args, Return>>;
// parameters match builderOrStrings, ...args
// args are mapped
// return of block function is based on report or command
Expand All @@ -175,13 +193,14 @@ interface TemplateEngine<TBlockType extends Block.ScratchType> {
*
*/
execute<
const This extends Framework.ExtensionInstance,
const This extends ExtensionInstance,
const Args extends any[],
const Return extends Block.ToReturnType<TBlockType>,
>
(
builder: (instance: This, tag: Utility.TaggedTemplate<Argument.MapToScratch<Args>, Block.Config>) => Block.Config
): Utility.TypedMethodDecorator<This, Args, Return, Utility.Method<This, Args, Return>>;
builder: (instance: This, tag: Utility.TaggedTemplate<Argument.MapToScratch<Args>, TypedMethodDecorator<This, Args, Return, Utility.Method<This, Args, Return>>>)
=> TypedMethodDecorator<This, Args, Return, Utility.Method<This, Args, Return>>
);
// function takes the string of Tagged Template
// parameters match builderOrStrings, ...args
// return of block function is based on report or command
Expand Down
8 changes: 7 additions & 1 deletion extensions/src/simple_example/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<string> = {
items: ['1', 'two', 'three'],
Expand Down Expand Up @@ -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: [
Expand Down

0 comments on commit 15b815e

Please sign in to comment.