1/* 2 * Copyright (c) 2023 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import { 17 factory, 18 isBindingElement, 19 isObjectBindingPattern, 20 isShorthandPropertyAssignment, 21 isSourceFile, 22 isStructDeclaration, 23 setParentRecursive, 24 visitEachChild, 25 isConstructorDeclaration 26} from 'typescript'; 27 28import type { 29 BindingElement, 30 ClassElement, 31 Expression, 32 Identifier, 33 Node, 34 SourceFile, 35 StructDeclaration, 36 TransformationContext, 37 Transformer, 38 TransformerFactory 39} from 'typescript'; 40 41import type {INameObfuscationOption} from '../../configs/INameObfuscationOption'; 42import type {TransformPlugin} from '../TransformPlugin'; 43import {TransformerOrder} from '../TransformPlugin'; 44import type {IOptions} from '../../configs/IOptions'; 45import {NodeUtils} from '../../utils/NodeUtils'; 46import {ArkObfuscator, performancePrinter} from '../../ArkObfuscator'; 47import { EventList, endSingleFileEvent, startSingleFileEvent } from '../../utils/PrinterUtils'; 48import { MemoryDottingDefine } from '../../utils/MemoryDottingDefine'; 49 50namespace secharmony { 51 const createShorthandPropertyTransformerFactory = function (option: IOptions): TransformerFactory<Node> | null { 52 let profile: INameObfuscationOption = option.mNameObfuscation; 53 if (!profile || !profile.mEnable) { 54 return null; 55 } 56 57 return shorthandPropertyTransformFactory; 58 59 function shorthandPropertyTransformFactory(context: TransformationContext): Transformer<Node> { 60 return shorthandPropertyTransformer; 61 62 function shorthandPropertyTransformer(node: Node): Node { 63 if (isSourceFile(node) && ArkObfuscator.isKeptCurrentFile) { 64 return node; 65 } 66 67 const recordInfo = ArkObfuscator.recordStage(MemoryDottingDefine.SHORTHAND_OBFUSCATION); 68 startSingleFileEvent(EventList.SHORT_HAND_OBFUSCATION, performancePrinter.timeSumPrinter); 69 let ret = transformShortHandProperty(node); 70 let parentNodes = setParentRecursive(ret, true); 71 endSingleFileEvent(EventList.SHORT_HAND_OBFUSCATION, performancePrinter.timeSumPrinter); 72 ArkObfuscator.stopRecordStage(recordInfo); 73 return parentNodes; 74 } 75 76 function transformShortHandProperty(node: Node): Node { 77 /** 78 * example: 79 * `let name1 = 'hello';` 80 * `let info = {name1};` 81 * obfuscated example: 82 * `let name1 = 'hello';`; 83 * `let info = {name1: name1};` 84 */ 85 if (isShorthandPropertyAssignment((node))) { 86 let initializer = node.objectAssignmentInitializer; 87 let expression: Expression = node.name; 88 if (initializer) { 89 expression = factory.createBinaryExpression(node.name, node.equalsToken, initializer); 90 } 91 92 let identifier = factory.createIdentifier(node.name.text); 93 return factory.createPropertyAssignment(identifier, expression); 94 } 95 96 /** 97 * exclude grammar instance: let [name2, age2] = ['akira', 22]; 98 * 99 * grammar: {name1, ...rest}= {'name1': 'akira', age : 22}; 100 * an alias will be created for name1. 101 * no alias will be created for rest. 102 * 103 * include grammars: 104 * orinal ObjectBinding(): 105 * const { name3, age3 } = foo3(); 106 * const { name4, addr4: { contry, place} } = foo4(); 107 * obfuscated ObjectBinding: 108 * `const { name3: name3, age3: age3 } = foo3();` 109 * `const { name4: name4, addr4: { contry: contry, place: place} } = { name4: 4, addr4: { contry:5, place:6} };` 110 */ 111 if (isElementsInObjectBindingPattern(node) && !node.propertyName && !node.dotDotDotToken) { 112 return factory.createBindingElement(node.dotDotDotToken, factory.createIdentifier((node.name as Identifier).text), 113 node.name, node.initializer); 114 } 115 116 return visitEachChild(node, transformShortHandProperty, context); 117 } 118 119 function isElementsInObjectBindingPattern(node: Node): node is BindingElement { 120 return node.parent && isObjectBindingPattern(node.parent) && isBindingElement(node); 121 } 122 } 123 }; 124 125 export let transformerPlugin: TransformPlugin = { 126 'name': 'ShortHandPropertyTransformer', 127 'order': TransformerOrder.SHORTHAND_PROPERTY_TRANSFORMER, 128 'createTransformerFactory': createShorthandPropertyTransformerFactory, 129 }; 130} 131 132export = secharmony; 133