diff --git a/arkoala/ets-plugin/src/StructTransformer.ts b/arkoala/ets-plugin/src/StructTransformer.ts index 986a01b3eaab69d7fe1cc4ebb6d82ebadc674264..2a9f729405495ba19617732becc9590f0b12d8a1 100644 --- a/arkoala/ets-plugin/src/StructTransformer.ts +++ b/arkoala/ets-plugin/src/StructTransformer.ts @@ -975,7 +975,9 @@ export class StructTransformer extends AbstractVisitor { const parentName = parent.name if (!parentName || !ts.isIdentifier(parentName)) return false const parentNameString = ts.idText(parentName) - + if (parentNameString.endsWith("Attribute") || parentNameString.endsWith("Method")) { + console.log(">>>\t\t[M] " + name.getText() + " of " + parentNameString) + } const ohosDeclaredClass = parentNameString.endsWith("Attribute") || parentNameString == "CommonMethod" @@ -1087,6 +1089,16 @@ export class StructTransformer extends AbstractVisitor { } visitor(beforeChildren: ts.Node): ts.Node { + if (ts.isEtsComponentExpression(beforeChildren) && ts.isIdentifier(beforeChildren.expression)) { + console.log(">>>\t[C] " + ts.idText(beforeChildren.expression)) + } + if (ts.isPropertyAssignment(beforeChildren)) { + const parent = beforeChildren.parent?.parent + if (ts.isEtsComponentExpression(parent) && ts.isIdentifier(parent.expression)) { + // const parentName = ts.idText(parent.expression) + console.log(">>>\t\t[O] " + beforeChildren.name.getText()) + } + } const node = this.visitEachChild(beforeChildren) if (ts.isStructDeclaration(node)) { return this.translateStructToClass(node) diff --git a/arkoala/ets-plugin/test/scripts/attributes-histogram.mjs b/arkoala/ets-plugin/test/scripts/attributes-histogram.mjs new file mode 100644 index 0000000000000000000000000000000000000000..074867f1559e87e07618b2713bfda7b401b7f126 --- /dev/null +++ b/arkoala/ets-plugin/test/scripts/attributes-histogram.mjs @@ -0,0 +1,188 @@ +// Parses an output of ets-plugin with component modifiers/options calls. +// Merges it by component or by super type and prints histogram with call frequency. + +import fs from "fs" + +const MERGE_BY_COMPONENT = "--by-component" +const MERGE_BY_SUPER_TYPE = "--by-super-type" + +const LOG_ENABLED = false + +function log(msg) { + if (LOG_ENABLED) console.log("> " + msg) +} + +const INPUT_FILE = process.argv[2] +const MERGE_BY = process.argv[3] ?? MERGE_BY_COMPONENT + +// 'modifier' - A property setter method called on a component. +// E.g.: Button().width(30) +// 'modifier type' - A component or a super component a modifier is called/defined on. +// E.g.: Button().width(30) - the type of 'width' is Button or Common. +// 'option' - A property of a component set via an object literal passed to the component's ctor. +// 'options variant' - A sorted list of options in a certain component ctor call. +// E.g.: Rect({height: 100, radius: 10, width: 200}) +// 'attribute' - A 'modifier' or 'options variant'. + +class TokenKind { + name + pattern + constructor(name, pattern) { + this.name = name + this.pattern = pattern + } + toString() { + return this.name + } +} + +class Token { + kind + value + constructor(kind, value) { + this.kind = kind + this.value = value + log(`token: ${this.toString()}`) + } + toString() { + return `${this.kind.name} [${this.value.join(", ")}]` + } +} + +const TK_COMPONENT = new TokenKind("Component", /^.*\[C]\s([a-zA-Z0-9]+)$/) +const TK_MODIFIER = new TokenKind("Modifier", /^.*\[M]\s(.+)\sof\s(.*)$/) +const TK_OPTION = new TokenKind("Option", /^.*\[O]\s(.+)$/) + +const COMPONENTS_MAP = new Map() + +// a variant being parsed +const KEY_UNCOMPLETED_OPTIONS_VARIANT = "KEY_UNCOMPLETED_OPTIONS_VARIANT" +const KEY_ALL_OPTIONS_VARIANTS = "KEY_ALL_OPTIONS_VARIANTS" + +function specialKey(key) { + return key === KEY_UNCOMPLETED_OPTIONS_VARIANT || key === KEY_ALL_OPTIONS_VARIANTS +} + +function main() { + let currentComponent = undefined + parseInput(token => { + switch (token.kind) { + case TK_COMPONENT: + componentExprCompleted(currentComponent) + currentComponent = token.value[0] + break + + case TK_MODIFIER: + let modifier = token.value[0] + let modifierType = token.value[1] + if (MERGE_BY === MERGE_BY_COMPONENT) { + modifier += ` (${modifierType})` + modifierType = currentComponent + } + addModifier(modifier, modifierType) + break + + case TK_OPTION: + if (MERGE_BY === MERGE_BY_COMPONENT) { + const option = token.value[0] + addOption(option, currentComponent) + } + break + } + }) + componentExprCompleted(currentComponent) + printHistogram() +} + +function parseInput(acceptToken) { + const content = fs.readFileSync(INPUT_FILE) + "" + content.split(/\r?\n/).forEach(token => { + let match = token.match(TK_COMPONENT.pattern) + if (match) { + const component = match.splice(1)[0] + acceptToken(new Token(TK_COMPONENT, [component])) + return + } + match = token.match(TK_MODIFIER.pattern) + if (match) { + const groups = match.splice(1) + const modifier = groups[0] + const modifierType = groups[1] + acceptToken(new Token(TK_MODIFIER, [modifier, modifierType])) + return + } + match = token.match(TK_OPTION.pattern) + if (match) { + const option = match.splice(1)[0] + acceptToken(new Token(TK_OPTION, [option])) + } + }) +} + +function addModifier(modifier, modifierType) { + const modifiersMap = COMPONENTS_MAP.get(modifierType) ?? new Map() + let freq = modifiersMap.get(modifier) ?? 0 + modifiersMap.set(modifier, ++freq) + COMPONENTS_MAP.set(modifierType, modifiersMap) +} + +function addOption(option, component) { + const optionsMap = COMPONENTS_MAP.get(component) ?? new Map() + const uncompleted = optionsMap.get(KEY_UNCOMPLETED_OPTIONS_VARIANT) ?? [] + let i = 0 + for (; i < uncompleted.length; i++) { + if (option < uncompleted[i]) break + } + uncompleted.splice(i, 0, option) + optionsMap.set(KEY_UNCOMPLETED_OPTIONS_VARIANT, uncompleted) + COMPONENTS_MAP.set(component, optionsMap) +} + +function componentExprCompleted(component) { + if (!component) { + return + } + const attributesMap = COMPONENTS_MAP.get(component) + if (!attributesMap) { + // just add 'component' + COMPONENTS_MAP.set(component, new Map()) + return + } + const uncompleted = attributesMap.get(KEY_UNCOMPLETED_OPTIONS_VARIANT) + if (uncompleted) { + attributesMap.set(KEY_UNCOMPLETED_OPTIONS_VARIANT, undefined) + const variant = uncompleted.join(", ") + + const allVariants = attributesMap.get(KEY_ALL_OPTIONS_VARIANTS) ?? new Map() + let freq = allVariants.get(variant) ?? 0 + allVariants.set(variant, ++freq) + attributesMap.set(KEY_ALL_OPTIONS_VARIANTS, allVariants) + } +} + +function printHistogram() { + if (MERGE_BY === MERGE_BY_COMPONENT) { + console.log("COMPONENT") + console.log("{OPTIONS}") + console.log(".ATTRIBUTE (SUPER TYPE) : FREQUENCY") + + } else if (MERGE_BY === MERGE_BY_SUPER_TYPE) { + console.log("COMPONENT (SUPER TYPE)") + console.log(".ATTRIBUTE : FREQUENCY") + } + COMPONENTS_MAP.forEach((attributesMap, attributeType) => { + console.log("----------------------") + console.log(attributeType) + const allVariants = attributesMap.get(KEY_ALL_OPTIONS_VARIANTS) ?? [] + allVariants.forEach((valueFreq, keyVariant) => { + console.log(`{${keyVariant}} : ${valueFreq}`) + }) + attributesMap.forEach((valueFreq, keyAttribute) => { + if (!specialKey(keyAttribute)) { + console.log(`.${keyAttribute} : ${valueFreq}`) + } + }) + }) +} + +main()