UNPKG

ben-sb-shift-codegen

Version:

code generator for Shift format ASTs (forked for use in https://github.com/ben-sb/javascript-deobfuscator)

127 lines (112 loc) 3.62 kB
/** * Copyright 2014 Shape Security, Inc. * * Licensed under the Apache License, Version 2.0 (the "License") * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * This file has been modified to prevent minifying of floats. * @ben-sb */ const { idContinueLargeRegex, idContinueBool } = require('./unicode'); function isIdentifierPartES6(char) { let charCode = char.charCodeAt(0); if (charCode < 128) { return idContinueBool[charCode]; } return idContinueLargeRegex.test(char); } function needsDoubleDot(fragment) { return fragment.indexOf('.') < 0 && fragment.indexOf('e') < 0 && fragment.indexOf('x') < 0; } function renderNumber(n) { if (n >= 1e3 && n % 10 === 0) { const s = n.toString(10); if (/[eE]/.test(s)) { return s.replace(/[eE]\+/, 'e'); } return s.replace(/0{3,}$/, match => { return 'e' + match.length; }); } else { if (n > 1e15 && n < 1e20) { return '0x' + n.toString(16).toUpperCase(); } return n.toString(10).replace(/[eE]\+/, 'e'); } } class TokenStream { constructor() { this.result = ''; this.lastNumber = null; this.lastCodePoint = null; this.lastTokenStr = ''; this.optionalSemi = false; this.previousWasRegExp = false; this.partialHtmlComment = false; } putNumber(number) { let tokenStr = renderNumber(number); this.put(tokenStr); this.lastNumber = tokenStr; } putOptionalSemi() { this.optionalSemi = true; } putRaw(tokenStr) { this.result += tokenStr; this.lastTokenStr = tokenStr; } put(tokenStr, isRegExp) { if (this.optionalSemi) { this.optionalSemi = false; if (tokenStr !== '}') { this.result += ';'; this.lastCodePoint = ';'; this.previousWasRegExp = false; } } if (this.lastNumber !== null && tokenStr.length === 1) { if (tokenStr === '.') { this.result += needsDoubleDot(this.lastNumber) ? '..' : '.'; this.lastNumber = null; this.lastCodePoint = '.'; return; } } let tokenStrCodePointCount = [...tokenStr].length; // slow, no unicode length? if (tokenStrCodePointCount > 0) { this.lastNumber = null; let rightCodePoint = String.fromCodePoint(tokenStr.codePointAt(0)); let lastCodePoint = this.lastCodePoint; this.lastCodePoint = String.fromCodePoint(tokenStr.codePointAt(tokenStrCodePointCount - 1)); let previousWasRegExp = this.previousWasRegExp; this.previousWasRegExp = isRegExp; if (lastCodePoint && ((lastCodePoint === '+' || lastCodePoint === '-') && lastCodePoint === rightCodePoint || isIdentifierPartES6(lastCodePoint) && isIdentifierPartES6(rightCodePoint) || lastCodePoint === '/' && rightCodePoint === '/' || previousWasRegExp && rightCodePoint === 'i' || this.partialHtmlComment && tokenStr.startsWith('--'))) { this.result += ' '; } } this.partialHtmlComment = this.lastTokenStr.endsWith('<') && tokenStr === '!'; this.result += tokenStr; this.lastTokenStr = tokenStr; } } module.exports = { needsDoubleDot, TokenStream, };