UNPKG

@kpi4me/golden-layout

Version:

A multi-screen javascript Layout manager https://golden-layout.com

381 lines (342 loc) 15.4 kB
do (exports = exports ? this.cscodegen = {}) -> TAB = ' ' indent = (code) -> ("#{TAB}#{line}" for line in code.split '\n').join '\n' parens = (code) -> "(#{code})" formatStringData = (data) -> data.replace /[^\x20-\x7e]|['\\]/, (c) -> switch c when '\0' then '\\0' when '\b' then '\\b' when '\t' then '\\t' when '\n' then '\\n' when '\f' then '\\f' when '\r' then '\\r' when '\'' then '\\\'' when '\\' then '\\\\' else escape = (c.charCodeAt 0).toString 16 pad = "0000"[escape.length...] "\\u#{pad}#{escape}" formatInterpolation = (ast, options) -> switch ast.className when "ConcatOp" left = formatInterpolation ast.left, options right = formatInterpolation ast.right, options "#{left}#{right}" when "String" formatStringData ast.data else "\#{#{generate ast, options}}" needsParensWhenOnLeft = (ast) -> switch ast.className when 'Function', 'BoundFunction', 'NewOp' then yes when 'Conditional', 'Switch', 'While', 'Block' then yes when 'PreIncrementOp', 'PreDecrementOp', 'UnaryPlusOp', 'UnaryNegateOp', 'LogicalNotOp', 'BitNotOp', 'DoOp', 'TypeofOp', 'DeleteOp' needsParensWhenOnLeft ast.expression when 'FunctionApplication' then ast.arguments.length > 0 else no eq = (nodeA, nodeB) -> for own prop, val of nodeA continue if prop in ['raw', 'line', 'column'] switch Object::toString.call val when '[object Object]' then return no unless eq nodeB[prop], val when '[object Array]' for v, i in val return no unless eq nodeB[prop][i], v else return no unless nodeB[prop] is val yes clone = (obj, overrides = {}) -> newObj = {} newObj[prop] = val for own prop, val of obj newObj[prop] = val for own prop, val of overrides newObj levels = [ ['SeqOp'] # Sequence ['Conditional', 'ForIn', 'ForOf', 'While'] # Control Flow ['FunctionApplication', 'SoakedFunctionApplication'] # Application ['AssignOp', 'CompoundAssignOp', 'ExistsAssignOp'] # Assignment ['LogicalOrOp'] # Logical OR ['LogicalAndOp'] # Logical AND ['BitOrOp'] # Bitwise OR ['BitXorOp'] # Bitwise XOR ['BitAndOp'] # Bitwise AND ['ExistsOp'] # Existential ['EQOp', 'NEQOp'] # Equality ['LTOp', 'LTEOp', 'GTOp', 'GTEOp', 'InOp', 'OfOp', 'InstanceofOp'] # Relational ['LeftShiftOp', 'SignedRightShiftOp', 'UnsignedRightShiftOp'] # Bitwise Shift ['PlusOp', 'SubtractOp'] # Additive ['MultiplyOp', 'DivideOp', 'RemOp'] # Multiplicative ['UnaryPlusOp', 'UnaryNegateOp', 'LogicalNotOp', 'BitNotOp', 'DoOp', 'TypeofOp', 'PreIncrementOp', 'PreDecrementOp', 'DeleteOp'] # Unary ['UnaryExistsOp', 'ShallowCopyArray', 'PostIncrementOp', 'PostDecrementOp', 'Spread'] # Postfix ['NewOp'] # New ['MemberAccessOp', 'SoakedMemberAccessOp', 'DynamicMemberAccessOp', 'SoakedDynamicMemberAccessOp', 'ProtoMemberAccessOp', 'DynamicProtoMemberAccessOp', 'SoakedProtoMemberAccessOp', 'SoakedDynamicProtoMemberAccessOp'] # Member ] precedence = {} do -> for ops, level in levels for op in ops precedence[op] = level operators = # Binary SeqOp: ';' LogicalOrOp: 'or', LogicalAndOp: 'and' BitOrOp: '|', BitXorOp: '^', BitAndOp: '&' EQOp: 'is', NEQOp: 'isnt', LTOp: '<', LTEOp: '<=', GTOp: '>', GTEOp: '>=' InOp: 'in', OfOp: 'of', InstanceofOp: 'instanceof' LeftShiftOp: '<<', SignedRightShiftOp: '>>', UnsignedRightShiftOp: '>>>' PlusOp: '+', SubtractOp: '-', MultiplyOp: '*', DivideOp: '/', RemOp: '%' # Prefix UnaryPlusOp: '+', UnaryNegateOp: '-', LogicalNotOp: 'not ', BitNotOp: '~' DoOp: 'do ', NewOp: 'new ', TypeofOp: 'typeof ' PreIncrementOp: '++', PreDecrementOp: '--' # Postfix UnaryExistsOp: '?' ShallowCopyArray: '[..]' PostIncrementOp: '++' PostDecrementOp: '--' Spread: '...' # Application FunctionApplication: '' SoakedFunctionApplication: '?' # Member MemberAccessOp: '.' SoakedMemberAccessOp: '?.' ProtoMemberAccessOp: '::' SoakedProtoMemberAccessOp: '?::' DynamicMemberAccessOp: '' SoakedDynamicMemberAccessOp: '?' DynamicProtoMemberAccessOp: '::' SoakedDynamicProtoMemberAccessOp: '?::' # TODO: DRY this function # TODO: ast as context? exports.generate = generate = (ast, options = {}) -> needsParens = no options.precedence ?= 0 options.ancestors ?= [] parent = options.ancestors[0] parentClassName = parent?.className usedAsExpression = parent? and parentClassName isnt 'Block' src = switch ast.className when 'Program' options.ancestors = [ast, options.ancestors...] if ast.body? then generate ast.body, options else '' when 'Block' options = clone options, ancestors: [ast, options.ancestors...] precedence: 0 if ast.statements.length is 0 then generate (new Undefined).g(), options else sep = if parentClassName is 'Program' then '\n\n' else '\n' (generate s, options for s in ast.statements).join sep when 'Conditional' options.ancestors.unshift ast options.precedence = 0 hasAlternate = ast.consequent? and ast.alternate? _consequent = generate (ast.consequent ? (new Undefined).g()), options _alternate = if hasAlternate then generate ast.alternate, options else "" isMultiline = _consequent.length > 90 or _alternate.length > 90 or '\n' in _alternate or '\n' in _consequent _consequent = if isMultiline then "\n#{indent _consequent}" else " then #{_consequent}" if hasAlternate _alternate = if isMultiline then "\nelse\n#{indent _alternate}" else " else #{_alternate}" "if #{generate ast.condition, options}#{_consequent}#{_alternate}" when 'Identifier' then ast.data when 'Null' then 'null' when 'This' then 'this' when 'Undefined' then 'undefined' when 'Int' absNum = if ast.data < 0 then -ast.data else ast.data # if number is a power of two (at least 2^4) or hex is a shorter # representation, represent it as hex if absNum >= 1e12 or (absNum >= 0x10 and 0 is (absNum & (absNum - 1))) "0x#{ast.data.toString 16}" else ast.data.toString 10 when 'Float' then ast.data.toString 10 when 'String' "'#{formatStringData ast.data}'" when 'ArrayInitialiser' options = clone options, ancestors: [ast, options.ancestors...] precedence: precedence.AssignmentExpression members_ = (generate m, options for m in ast.members) switch ast.members.length when 0 then '[]' when 1, 2 for m, i in members_ when i + 1 isnt members_.length members_[i] = parens m if needsParensWhenOnLeft ast.members[i] "[#{members_.join ', '}]" else "[\n#{indent members_.join '\n'}\n]" when 'ObjectInitialiser' options.ancestors = [ast, options.ancestors...] members_ = (generate m, options for m in ast.members) switch ast.members.length when 0 then '{}' when 1 then "{#{members_.join ', '}}" else "{\n#{indent members_.join '\n'}\n}" when 'ObjectInitialiserMember' options = clone options, ancestors: [ast, options.ancestors...] precedence: precedence.AssignmentExpression key_ = generate ast.key, options expression_ = generate ast.expression, options memberAccessOps = ['MemberAccessOp', 'ProtoMemberAccessOp', 'SoakedMemberAccessOp', 'SoakedProtoMemberAccessOp'] if eq ast.key, ast.expression "#{key_}" else if ast.expression.className in memberAccessOps and ast.key.data is ast.expression.memberName "#{expression_}" else "#{key_}: #{expression_}" when 'Function', 'BoundFunction' options = clone options, ancestors: [ast, options.ancestors...] precedence: precedence.AssignmentExpression parameters = (generate p, options for p in ast.parameters) options.precedence = 0 _body = if !ast.body? or ast.body.className is 'Undefined' then '' else generate ast.body, options _paramList = if ast.parameters.length > 0 then "(#{parameters.join ', '}) " else '' _block = if _body.length is 0 then '' else if _paramList.length + _body.length < 100 and '\n' not in _body then " #{_body}" else "\n#{indent _body}" switch ast.className when 'Function' then "#{_paramList}->#{_block}" when 'BoundFunction' then "#{_paramList}=>#{_block}" when 'AssignOp' prec = precedence[ast.className] needsParens = prec < options.precedence options = clone options, ancestors: [ast, options.ancestors...] precedence: prec _assignee = generate ast.assignee, options _expr = generate ast.expression, options "#{_assignee} = #{_expr}" when 'CompoundAssignOp' prec = precedence[ast.className] needsParens = prec < options.precedence options = clone options, ancestors: [ast, options.ancestors...] precedence: prec _op = operators[ast.op::className] _assignee = generate ast.assignee, options _expr = generate ast.expression, options "#{_assignee} #{_op}= #{_expr}" when 'SeqOp' prec = precedence[ast.className] needsParens = prec < options.precedence options = clone options, ancestors: [ast, options.ancestors...] precedence: prec _left = generate ast.left, options _right = generate ast.right, options "#{_left}; #{_right}" when 'LogicalOrOp', 'LogicalAndOp', 'BitOrOp', 'BitXorOp', 'BitAndOp', 'LeftShiftOp', 'SignedRightShiftOp', 'UnsignedRightShiftOp', 'EQOp', 'NEQOp', 'LTOp', 'LTEOp', 'GTOp', 'GTEOp', 'InOp', 'OfOp', 'InstanceofOp', 'PlusOp', 'SubtractOp', 'MultiplyOp', 'DivideOp', 'RemOp', 'ExistsOp' _op = operators[ast.className] if ast.className in ['InOp', 'OfOp', 'InstanceofOp'] and parentClassName is 'LogicalNotOp' _op = "not #{_op}" prec = precedence[ast.className] needsParens = prec < options.precedence options = clone options, ancestors: [ast, options.ancestors...] precedence: prec _left = generate ast.left, options _left = parens _left if needsParensWhenOnLeft ast.left _right = generate ast.right, options "#{_left} #{_op} #{_right}" when 'UnaryPlusOp', 'UnaryNegateOp', 'LogicalNotOp', 'BitNotOp', 'DoOp', 'TypeofOp', 'PreIncrementOp', 'PreDecrementOp' _op = operators[ast.className] prec = precedence[ast.className] if ast.className is 'LogicalNotOp' if ast.expression.className in ['InOp', 'OfOp', 'InstanceofOp'] _op = '' # these will be treated as negated variants prec = precedence[ast.expression.className] if 'LogicalNotOp' in [parentClassName, ast.expression.className] _op = '!' needsParens = prec < options.precedence needsParens = yes if parentClassName is ast.className and ast.className in ['UnaryPlusOp', 'UnaryNegateOp'] options = clone options, ancestors: [ast, options.ancestors...] precedence: prec "#{_op}#{generate ast.expression, options}" when 'UnaryExistsOp', 'PostIncrementOp', 'PostDecrementOp', 'Spread' _op = operators[ast.className] prec = precedence[ast.className] needsParens = prec < options.precedence options = clone options, ancestors: [ast, options.ancestors...] precedence: prec _expr = generate ast.expression, options _expr = parens _expr if needsParensWhenOnLeft ast.expression "#{_expr}#{_op}" when 'NewOp' _op = operators[ast.className] prec = precedence[ast.className] options = clone options, ancestors: [ast, options.ancestors...] precedence: prec _ctor = generate ast.ctor, options _ctor = parens _ctor if ast.arguments.length > 0 and needsParensWhenOnLeft ast.ctor options.precedence = precedence['AssignOp'] args = for a, i in ast.arguments arg = generate a, options arg = parens arg if (needsParensWhenOnLeft a) and i + 1 isnt ast.arguments.length arg _args = if ast.arguments.length is 0 then '' else " #{args.join ', '}" "#{_op}#{_ctor}#{_args}" when 'FunctionApplication', 'SoakedFunctionApplication' if ast.className is 'FunctionApplication' and ast.arguments.length is 0 and not usedAsExpression generate (new DoOp ast.function), options else options = clone options, ancestors: [ast, options.ancestors...] precedence: precedence[ast.className] _op = operators[ast.className] _fn = generate ast.function, options _fn = parens _fn if needsParensWhenOnLeft ast.function args = for a, i in ast.arguments arg = generate a, options arg = parens arg if (needsParensWhenOnLeft a) and i + 1 isnt ast.arguments.length arg _argList = if ast.arguments.length is 0 then '()' else " #{args.join ', '}" "#{_fn}#{_op}#{_argList}" when 'MemberAccessOp', 'SoakedMemberAccessOp', 'ProtoMemberAccessOp', 'SoakedProtoMemberAccessOp' _op = operators[ast.className] prec = precedence[ast.className] needsParens = prec < options.precedence options = clone options, ancestors: [ast, options.ancestors...] precedence: prec if ast.expression.className is 'This' _expr = '@' _op = '' if ast.className is 'MemberAccessOp' else _expr = generate ast.expression, options _expr = parens _expr if needsParensWhenOnLeft ast.expression "#{_expr}#{_op}#{ast.memberName}" when 'DynamicMemberAccessOp', 'SoakedDynamicMemberAccessOp', 'DynamicProtoMemberAccessOp', 'SoakedDynamicProtoMemberAccessOp' _op = operators[ast.className] prec = precedence[ast.className] needsParens = prec < options.precedence options = clone options, ancestors: [ast, options.ancestors...] precedence: prec if ast.expression.className is 'This' _expr = '@' else _expr = generate ast.expression, options _expr = parens _expr if needsParensWhenOnLeft ast.expression options.precedence = 0 _indexingExpr = generate ast.indexingExpr, options "#{_expr}#{_op}[#{_indexingExpr}]" when 'ConcatOp' _left = formatInterpolation ast.left, options _right = formatInterpolation ast.right, options "\"#{_left}#{_right}\"" else throw new Error "Non-exhaustive patterns in case: #{ast.className}" if needsParens then (parens src) else src