function getRuntimeMarkDecl(blockPath) { let block = blockPath.node; assert.ok(Array.isArray(block.body)); let info = getMarkInfo(block); if (info.decl) { return info.decl; } info.decl = t.variableDeclaration("var", [ t.variableDeclarator( blockPath.scope.generateUidIdentifier("marked"), t.callExpression( t.memberExpression( t.arrayExpression([]), t.identifier("map"), false ), [util.runtimeProperty("mark")] ) ) ]); blockPath.unshiftContainer("body", info.decl); return info.decl; }
Ep.getTryLocsList = function() { if (this.tryEntries.length === 0) { // To avoid adding a needless [] to the majority of runtime.wrap // argument lists, force the caller to handle this case specially. return null; } let lastLocValue = 0; return t.arrayExpression( this.tryEntries.map(function(tryEntry) { let thisLocValue = tryEntry.firstLoc.value; assert.ok(thisLocValue >= lastLocValue, "try entries out of order"); lastLocValue = thisLocValue; let ce = tryEntry.catchEntry; let fe = tryEntry.finallyEntry; let locs = [ tryEntry.firstLoc, // The null here makes a hole in the array. ce ? ce.firstLoc : null ]; if (fe) { locs[2] = fe.firstLoc; locs[3] = fe.afterLoc; } return t.arrayExpression(locs); }) ); };
it("analyses the body of a callback that has been passed as argument", function () { // arrange const predicateDeclaration = functionDeclaration(t.identifier("isEven"), t.identifier("x")); // body x % 2 === 0; const predicate = new FunctionType(VoidType.create(), [TypeVariable.create()], TypeVariable.create(), predicateDeclaration); const x = new Symbol("x", SymbolFlags.Variable); program.symbolTable.setSymbol(predicateDeclaration.params[0], x); const elementType = TypeVariable.create(); const predicateExpectedSignature = new FunctionType(VoidType.create(), [elementType], BooleanType.create()); const filter = new FunctionType(VoidType.create(), [ArrayType.of(elementType), predicateExpectedSignature], ArrayType.of(elementType)); const callExpression = t.callExpression(t.identifier("filter"), [t.arrayExpression([t.numericLiteral(1), t.numericLiteral(2)]), t.identifier("isEven")]); const callContext = context.fresh(); typeInferenceAnalysis.infer.withArgs(callExpression.callee).returns(filter); typeInferenceAnalysis.infer.withArgs(callExpression.arguments[0]).returns(ArrayType.of(NumberType.create())); typeInferenceAnalysis.infer.withArgs(callExpression.arguments[1]).returns(predicate); sinon.stub(context, "fresh").returns(callContext); sinon.stub(context, "unify").returnsArg(0); // return the actual argument type // unifying the parameter with the argument type requires that the type variables in the parameter type are substituted callContext.unify = (t1, t2) => { if (t1 instanceof ArrayType && t1.of instanceof NumberType && t2 instanceof ArrayType && t2.of instanceof TypeVariable) { callContext.substitute(t2.of, t1.of); return t2; } }; // Fake analysis of the predicate function by setting the return type callContext.analyse = () => callContext.typeEnvironment = callContext.typeEnvironment.setType(Symbol.RETURN, BooleanType.create()); // expect expect(rule.refine(callExpression, context)).to.be.instanceOf(ArrayType).and.to.have.property("of").that.is.an.instanceOf(NumberType); });
export let test = opts => { let tests = (prop, valid) => { return value => { return t.objectExpression([ t.objectProperty( t.identifier('fixture'), t.stringLiteral(`${prop}: ${value}`) ), t.objectProperty( t.identifier('valid'), t.identifier(valid ? 'true' : 'false') ) ]); }; }; let program = t.program([ template('module.exports = EXPORTS;')({ EXPORTS: t.arrayExpression(flatten(opts.properties.map(prop => { const valid = opts.valid.map(tests(prop, true)); const invalid = opts.invalid.map(tests(prop, false)); return valid.concat(invalid); }))) }) ]); return warning() + generate(program).code; };
export function push(mutatorMap: Object, node: Object, kind: string, file, scope?): Object { let alias = t.toKeyAlias(node); // let map = {}; if (has(mutatorMap, alias)) map = mutatorMap[alias]; mutatorMap[alias] = map; // map._inherits = map._inherits || []; map._inherits.push(node); map._key = node.key; if (node.computed) { map._computed = true; } if (node.decorators) { let decorators = map.decorators = map.decorators || t.arrayExpression([]); decorators.elements = decorators.elements.concat(node.decorators.map(dec => dec.expression).reverse()); } if (map.value || map.initializer) { throw file.buildCodeFrameError(node, "Key conflict with sibling node"); } let key, value; // save the key so we can possibly do function name inferences if (t.isObjectProperty(node) || t.isObjectMethod(node) || t.isClassMethod(node)) { key = t.toComputedKey(node, node.key); } if (t.isObjectProperty(node) || t.isClassProperty(node)) { value = node.value; } else if (t.isObjectMethod(node) || t.isClassMethod(node)) { value = t.functionExpression(null, node.params, node.body, node.generator, node.async); } let inheritedKind = toKind(node); if (!kind || inheritedKind !== "value") { kind = inheritedKind; } // infer function name if (scope && t.isStringLiteral(key) && (kind === "value" || kind === "initializer") && t.isFunctionExpression(value)) { value = nameFunction({ id: key, node: value, scope }); } if (value) { t.inheritsComments(value, node); map[kind] = value; } return map; }
export default opts => { const tests = opts.candidates.reduce((list, candidate) => { if (candidate.type === 'keyword') { list.push( createTest(candidate.value), createTest(candidate.value.toUpperCase()), ); } if (candidate.type === 'data') { const camel = camelCase(candidate.value); if (fixtures[camel]) { // eslint-disable-line const values = fixtures[camel].fixtures; // eslint-disable-line list.push.apply(list, values.valid.map(fixture => { return createTest(fixture); })); list.push.apply(list, values.invalid.map(fixture => { return createTest(fixture, false); })); if (candidate.min === 1 && candidate.max === false && candidate.separator === ',') { list.push( createTest(`${values.valid[0]}, ${values.valid[0]}`), createTest(`${values.valid[0]}, ${values.valid[0]},`, false), createTest(`var(--foo), var(--bar)`), createTest(`var(--foo), var(--bar),`, false) ); } } } return list; }, [...globals, ...globals.map(val => val.toUpperCase()), 'var(--foo)'].map(ident => createTest(ident))); if (opts.properties.length === 1) { return generateProgram([ template(`const property = PROPERTY;`)({ PROPERTY: t.stringLiteral(opts.properties[0]), }), template(`export default SUITE;`)({ SUITE: t.arrayExpression(tests), }), ]); } return generateProgram([ template(` export default PROPERTIES.reduce((suite, property) => { SUITE; return suite; }, []); `)({ PROPERTIES: arrayOfStrings(opts.properties), SUITE: t.callExpression( t.memberExpression( t.identifier('suite'), t.identifier('push') ), tests), }), ]); };
var formCSSXElement = function (args, pure) { return t.callExpression( t.memberExpression( t.identifier('cssx'), t.identifier('push') ), [t.arrayExpression(args)] ); };
export function toComputedObjectFromClass(obj: Object): Object { let objExpr = t.arrayExpression([]); for (let i = 0; i < obj.properties.length; i++) { let prop = obj.properties[i]; let val = prop.value; val.properties.unshift(t.objectProperty(t.identifier("key"), t.toComputedKey(prop))); objExpr.elements.push(val); } return objExpr; }
export let exportModules = exported => { const exportTemplate = template('module.exports = EXPORTS'); let ast = exportTemplate({ EXPORTS: t.arrayExpression(exported.map((value, index) => { if (index === exported.length - 1) { return t.identifier(`\n ${value}\n`); } return t.identifier(`\n ${value}`); })) }); return generate(ast).code + '\n'; };
it("replaces declaration in ExportDefaultDeclaration node", function() { traverse(ast, { FunctionDeclaration(path) { path.replaceWith(t.arrayExpression([ t.functionExpression( path.node.id, path.node.params, path.node.body, path.node.generator, path.node.async ), ])); }, }); assert(ast.program.body[0].declaration.type == "ArrayExpression"); });
processRule = function (rule) { propAssignment = t.expressionStatement( t.assignmentExpression( '=', t.memberExpression( t.identifier(id), rule.key, true ), isArray(rule.value.value) ? t.arrayExpression(rule.value.value.map(function (v) { return t.stringLiteral(v); })) : rule.value ) ); addToContext(propAssignment); };
TemplateLiteral : function(path, state){ var rawCode = _.trim(this.file.code.substring(path.node.start, path.node.end), '`'); var defaultOptions = { prefix : 'sql:', mode:'lodash' }; var options = _.assign({}, defaultOptions, state.opts); //如果不命中则直接返回 if(rawCode.substring(0, options.prefix.length).toLowerCase() != options.prefix.toLowerCase()){ return; }else{ rawCode = rawCode.substring(options.prefix.length); } //parse and gen code var ast = SQLParser.parse(rawCode); ast.yy = SQLParser.yy; ast.yy.clear(); var code = SQLComplile.exec(ast, { mode:options.mode, rawCode:rawCode }, path); if(options.debug){ console.log(rawCode, '==>', code); } //save the TemplateLiteral expressions var preexp = path.node.expressions; var replacement = babylon.parse( '(' + code + ')' , {plugins:['objectRestSpread']}); replacement = replacement.program.body[0].expression; //path.replaceWithSourceString(code); path.replaceWith( t.callExpression(replacement, [t.arrayExpression(preexp)]) ); }
this.tryEntries.map(function(tryEntry) { let thisLocValue = tryEntry.firstLoc.value; assert.ok(thisLocValue >= lastLocValue, "try entries out of order"); lastLocValue = thisLocValue; let ce = tryEntry.catchEntry; let fe = tryEntry.finallyEntry; let locs = [ tryEntry.firstLoc, // The null here makes a hole in the array. ce ? ce.firstLoc : null ]; if (fe) { locs[2] = fe.firstLoc; locs[3] = fe.afterLoc; } return t.arrayExpression(locs); })
it("it throws if the return type of the callback is not a subtype of the expected return type for the callback", function () { // arrange const predicateDeclaration = functionDeclaration(t.identifier("isEven"), t.identifier("x")); // body return null; const predicate = new FunctionType(VoidType.create(), [TypeVariable.create()], TypeVariable.create(), predicateDeclaration); const x = new Symbol("x", SymbolFlags.Variable); program.symbolTable.setSymbol(predicateDeclaration.params[0], x); const elementType = TypeVariable.create(); const predicateExpectedSignature = new FunctionType(VoidType.create(), [elementType], elementType); const filter = new FunctionType(VoidType.create(), [ArrayType.of(elementType), predicateExpectedSignature], ArrayType.of(elementType)); const callExpression = t.callExpression(t.identifier("map"), [t.arrayExpression([t.numericLiteral(1), t.numericLiteral(2)]), t.identifier("isEven")]); const callContext = context.fresh(); sinon.stub(context, "fresh").returns(callContext); // unifying the parameter with the argument type requires that the type variables in the parameter type are substituted callContext.unify = (t1, t2) => { if (t1 instanceof ArrayType && t1.of instanceof NumberType && t2 instanceof ArrayType && t2.of instanceof TypeVariable) { callContext.substitute(t2.of, t1.of); return t2; } if (t1 instanceof NumberType && t2 instanceof NullType) { return MaybeType.of(t1); } }; typeInferenceAnalysis.infer.withArgs(callExpression.callee).returns(filter); typeInferenceAnalysis.infer.withArgs(callExpression.arguments[0]).returns(ArrayType.of(NumberType.create())); typeInferenceAnalysis.infer.withArgs(callExpression.arguments[1]).returns(predicate); typeInferenceAnalysis.unify.returnsArg(0); // return the actual argument type // Fake analysis of the predicate function by setting the return type callContext.analyse = () => callContext.typeEnvironment = callContext.typeEnvironment.setType(Symbol.RETURN, NullType.create()); // expect expect(() => rule.refine(callExpression, context)).to.throw("Type inference failure: The return type 'null' of the callback is not a subtype of the return type 'number' of the expected callback."); });
function buildUmd(namespace, builder) { let body = []; body.push(t.variableDeclaration("var", [ t.variableDeclarator(namespace, t.identifier("global")) ])); builder(body); return t.program([ buildUmdWrapper({ FACTORY_PARAMETERS: t.identifier("global"), BROWSER_ARGUMENTS: t.assignmentExpression( "=", t.memberExpression(t.identifier("root"), namespace), t.objectExpression([]) ), COMMON_ARGUMENTS: t.identifier("exports"), AMD_ARGUMENTS: t.arrayExpression([t.stringLiteral("exports")]), FACTORY_BODY: body, UMD_ROOT: t.identifier("this") }) ]); }
rulesRegistration = rulesRegistration.reduce(function (result, current) { var name; if (current.expression && current.expression.left) { name = current.expression.left.property.value; if (name && rulesBuffer[name]) { if (result[rulesBuffer[name].index].expression.right.type === 'ArrayExpression') { result[rulesBuffer[name].index].expression.right.elements.push( t.identifier(current.expression.right.name) ); } else { result[rulesBuffer[name].index].expression.right = t.arrayExpression([ t.identifier(rulesBuffer[name].rule.expression.right.name), t.identifier(current.expression.right.name) ]); } } else { rulesBuffer[name] = { index: result.length, rule: current }; result.push(current); } } return result; }, []);
export let plugin = () => { const dependencies = [ requireModule({ identifier: 'validators', module: `./properties/` }), requireModule({ identifier: 'valueParser', module: `postcss-value-parser` }) ]; const tmpl = template(` module.exports = function isValid (cssString) { var parts = cssString.split(':').map(function (value) { return value.trim(); }); var parsed = valueParser(parts[1]); if (parsed.nodes.length === 1 && ~GLOBALS.indexOf(parsed.nodes[0].value)) { return true; } var invalid = validators.some(function (validator) { if (!~validator.properties.indexOf(parts[0])) { return; } return !validator(parsed); }); return !invalid; } `); let program = t.program([ tmpl({ GLOBALS: t.arrayExpression(globals.map(toStringLiteral)) }) ]); return warning() + dependencies.join('') + generate(program).code; };
function setParentCondition(jsx, expr, array = false) { const conditionExpr = jsx.findParent(p => p.isConditionalExpression()); const logicExpr = jsx.findParent(p => p.isLogicalExpression({ operator: '&&' })); if (array) { const ifAttrSet = new Set([ adapter_1.Adapter.if, adapter_1.Adapter.else ]); const logicalJSX = jsx.findParent(p => p.isJSXElement() && p.node.openingElement.attributes.some(a => ifAttrSet.has(a.name.name))); if (logicalJSX) { const attr = logicalJSX.node.openingElement.attributes.find(a => ifAttrSet.has(a.name.name)); if (attr) { if (attr.name.name === adapter_1.Adapter.else) { const prevElement = logicalJSX.getPrevSibling(); if (prevElement && prevElement.isJSXElement()) { const attr = prevElement.node.openingElement.attributes.find(a => a.name.name === adapter_1.Adapter.if); if (attr && t.isJSXExpressionContainer(attr.value)) { expr = t.conditionalExpression(reverseBoolean(lodash_1.cloneDeep(attr.value.expression)), expr, t.arrayExpression()); return expr; } } } else if (t.isJSXExpressionContainer(attr.value)) { expr = t.conditionalExpression(lodash_1.cloneDeep(attr.value.expression), expr, t.arrayExpression()); return expr; } } } } if (conditionExpr && conditionExpr.isConditionalExpression()) { const consequent = conditionExpr.get('consequent'); if (consequent === jsx || jsx.findParent(p => p === consequent)) { expr = t.conditionalExpression(lodash_1.cloneDeep(conditionExpr.get('test').node), expr, array ? t.arrayExpression([]) : t.nullLiteral()); } } if (logicExpr && logicExpr.isLogicalExpression({ operator: '&&' })) { const consequent = logicExpr.get('right'); if (consequent === jsx || jsx.findParent(p => p === consequent)) { expr = t.conditionalExpression(lodash_1.cloneDeep(logicExpr.get('left').node), expr, array ? t.arrayExpression([]) : t.nullLiteral()); } } return expr; }
compile: function(){ var ast = []; if (this.pp) { ast.push(t.variableDeclaration('var', [t.variableDeclarator(t.identifier('pug_indent'), t.arrayExpression())])); } push.apply(ast, this.visit(this.node)); if (!this.dynamicMixins) { // if there are no dynamic mixins we can remove any un-used mixins var mixinNames = Object.keys(this.mixins); for (var i = 0; i < mixinNames.length; i++) { var mixin = this.mixins[mixinNames[i]]; if (!mixin.used) { for (var x = 0; x < mixin.instances.length; x++) { mixin.instances[x].stmt.type = "EmptyStatement"; delete mixin.instances[x].stmt.expression; } } } } if (this.options.self) { ast = [ t.variableDeclaration('var', [ t.variableDeclarator(t.identifier('self'), t.logicalExpression('||', t.identifier('locals'), t.objectExpression([]))) ]) ].concat(ast); } else { // transform `ast` into `with(locals || {}) { ast }` ast = this.ast_with(ast); } if (this.debug) { if (this.options.includeSources) { ast.unshift(t.variableDeclaration('var', [ t.variableDeclarator(t.identifier('pug_debug_sources'), this.parseExpr(stringify(this.options.includeSources))) ])) } var rethrowArgs = [ t.identifier('err'), t.identifier('pug_debug_filename'), t.identifier('pug_debug_line') ] if (this.options.includeSources) { rethrowArgs.push(t.memberExpression(t.identifier('pug_debug_sources'), t.identifier('pug_debug_filename'), true)) } ast = [ t.variableDeclaration('var', [ t.variableDeclarator(t.identifier('pug_debug_filename'), null), t.variableDeclarator(t.identifier('pug_debug_line'), null) ]), t.tryStatement( t.blockStatement(ast), t.catchClause( t.identifier('err'), t.blockStatement([t.expressionStatement(t.callExpression( (this.inlineRuntimeFunctions ? t.identifier('pug_rethrow') : t.memberExpression(t.identifier('pug'), t.identifier('rethrow'))), rethrowArgs ))]) ) ) ] } ast = t.functionDeclaration( t.identifier(this.options.templateName || 'template'), this.templateVars.map(function(v) { return t.identifier(v)}), t.blockStatement([this.ast_variableDeclaration()].concat(ast, this.ast_return())) ) ast = this.ast_postprocess(ast); return buildRuntime(this.runtimeFunctionsUsed) + gen.default(ast).code; },
function constructCommonModule (moduleBody, deps) { return commonModuleTmpl({ MODULE_BODY: moduleBody, DEPS: t.arrayExpression(deps.map(dep => t.stringLiteral(dep.id))) }); }
exit: function (node, parent, index, context) { var rulesRegistration; var newStylesheetExpr; var createSelfInvoke; var funcExpr; var funcCallExpr; var result; var options = this.options; var applyResult = function (r) { if (isArray(parent)) { injectAt(parent, index, r); } else { parent[index] = r; } }; delete context.addToCSSXSelfInvoke; if (node.body.length === 0) { delete parent[index]; return; } // make sure that we keep the stylesheet definitions if (checkForStyleDefinition(node)) { applyResult(node.body[0]); return; } newStylesheetExpr = t.variableDeclaration( 'var', [ t.variableDeclarator( t.identifier(stylesheetId), this.options.format === 'object' ? t.objectExpression([]) : t.arrayExpression() ) ] ); rulesRegistration = node.body.map(function (line) { line = updateStyleSheet(line, stylesheetId, options); if (line.type === 'CallExpression') { line = t.expressionStatement(updateStyleSheet(line, stylesheetId, options)); } return line; }); // styles for only one rule if ( objectLiterals.length >= 1 && (typeof objectLiterals[0].selector === 'object' ? objectLiterals[0].selector.value === '' : objectLiterals[0].selector === '') ) { funcLines.push(t.returnStatement(t.identifier(objectLiterals[0].rulesObjVar))); } else { funcLines.push(newStylesheetExpr); funcLines = funcLines.concat(rulesRegistration); funcLines.push(t.returnStatement(t.identifier(stylesheetId))); } createSelfInvoke = function (expr) { return t.parenthesizedExpression(expr); }; // wrapping up the self-invoke function funcExpr = t.functionExpression(null, [], t.blockStatement(funcLines)); funcCallExpr = t.callExpression( t.memberExpression(funcExpr, t.identifier('apply')), [t.thisExpression()] ); result = createSelfInvoke(funcCallExpr); applyResult(result); }
visitMixin: function(mixin){ var ast = []; var self = this; var name = 'pug_mixins['; var args = mixin.args || ''; var block = mixin.block; var attrs = mixin.attrs; var attrsBlocks = this.attributeBlocks(mixin.attributeBlocks); var pp = this.pp; var dynamic = mixin.name[0]==='#'; var key = mixin.name; if (dynamic) this.dynamicMixins = true; name += (dynamic ? mixin.name.substr(2,mixin.name.length-3):'"'+mixin.name+'"')+']'; var mixinName = dynamic ? (mixin.astName || this.parseExpr(mixin.name.substr(2,mixin.name.length-3))): t.stringLiteral(mixin.name); this.mixins[key] = this.mixins[key] || {used: false, instances: []}; // mixin invocation if (mixin.call) { this.mixins[key].used = true; if (pp) { ast.push(t.expressionStatement(t.callExpression( t.memberExpression(t.identifier('pug_indent'), t.identifier('push')), [t.stringLiteral(Array(this.indents + 1).join(pp))] ))) } if (block || attrs.length || attrsBlocks.length) { var astArgs = [] ast.push( t.expressionStatement(this.wrapCallExpression(t.callExpression( t.memberExpression( t.memberExpression(t.identifier('pug_mixins'), mixinName, true), t.identifier("call") ), astArgs ))) ); var astObj, astKey; if (block || attrsBlocks.length || attrs.length) { astKey = []; astObj = t.objectExpression(astKey); astArgs.push(astObj); } if (block) { var astFunc = []; // Render block with no indents, dynamically added when rendered this.parentIndents++; var _indents = this.indents; this.indents = 0; push.apply(astFunc, this.visit(mixin.block, mixin)); this.indents = _indents; this.parentIndents--; astKey.push(t.objectProperty( t.identifier('block'), t.functionExpression( null, [], t.blockStatement(astFunc), this.useGenerators ) )); } if (attrsBlocks.length) { if (attrs.length) { var val = this.attrs(attrs); attrsBlocks.unshift(val); } if (attrsBlocks.length > 1) { astKey.push(t.objectProperty( t.identifier('attributes'), t.callExpression( this.runtime('merge', true), attrsBlocks.map(function(b) { return self.parseExpr(b) }) ) )); } else { astKey.push(t.objectProperty( t.identifier('attributes'), this.parseExpr(attrsBlocks[0]) )); } } else if (attrs.length) { var val = this.attrs(attrs); astKey.push(t.objectProperty( t.identifier('attributes'), this.parseExpr(val) )); } if (args) { args = args ? args.split(',') : []; Array.prototype.push.apply(astArgs, mixin.astArgs || this.parseArgs(args) ) } } else { var astArgs = mixin.astArgs || this.parseArgs(args); ast.push(t.expressionStatement(this.wrapCallExpression(t.callExpression( t.memberExpression(t.identifier('pug_mixins'), mixinName, true), astArgs )))); } if (pp) { ast.push(t.expressionStatement(t.callExpression( t.memberExpression(t.identifier('pug_indent'), t.identifier('pop')), [] ))) } } // mixin definition else { args = args ? args.split(',') : []; var rest; if (args.length && /^\.\.\./.test(args[args.length - 1].trim())) { rest = args.pop().trim().replace(/^\.\.\./, ''); } var astArgs = args.map(function(arg) { return t.identifier(arg.trim())}) // we need use pug_interp here for v8: https://code.google.com/p/v8/issues/detail?id=4165 // once fixed, use this: this.buf.push(name + ' = function(' + args.join(',') + '){'); var astMixin = []; astMixin.push( t.variableDeclaration('var', [ t.variableDeclarator( t.identifier('block'), t.logicalExpression('&&', t.thisExpression(), t.memberExpression(t.thisExpression(), t.identifier('block'))) ), t.variableDeclarator( t.identifier('attributes'), t.logicalExpression('||', t.logicalExpression('&&', t.thisExpression(), t.memberExpression(t.thisExpression(), t.identifier('attributes'))), t.objectExpression([]) ) ) ]) ) if (rest) { astMixin.push( t.variableDeclaration('var', [ t.variableDeclarator( t.identifier(rest), t.arrayExpression([]) ) ]) ) astMixin.push( t.forStatement( t.assignmentExpression('=', t.identifier('pug_interp'), t.numericLiteral(args.length)), t.binaryExpression('<', t.identifier('pug_interp'), t.memberExpression(t.identifier('arguments'), t.identifier('length'))), t.updateExpression('++', t.identifier('pug_interp'), false), t.expressionStatement( t.callExpression( t.memberExpression(t.identifier(rest), t.identifier('push')), [t.memberExpression(t.identifier('arguments'), t.identifier('pug_interp'), true)] ) ) ) ) } this.parentIndents++; push.apply(astMixin, this.visit(block, mixin)); this.parentIndents--; var mixinStmt = t.expressionStatement( t.assignmentExpression( '=', t.memberExpression(t.identifier('pug_mixins'), mixinName, true), t.assignmentExpression( '=', t.identifier('pug_interp'), t.functionExpression( null, astArgs, t.blockStatement(astMixin), this.useGenerators ) ) ) ); ast.push(mixinStmt); this.mixins[key].instances.push({stmt: mixinStmt}); } return ast; },
Ep.explodeExpression = function(path, ignoreResult) { let expr = path.node; if (expr) { t.assertExpression(expr); } else { return expr; } let self = this; let result; // Used optionally by several cases below. let after; function finish(expr) { t.assertExpression(expr); if (ignoreResult) { self.emit(expr); } else { return expr; } } // If the expression does not contain a leap, then we either emit the // expression as a standalone statement or return it whole. if (!meta.containsLeap(expr)) { return finish(expr); } // If any child contains a leap (such as a yield or labeled continue or // break statement), then any sibling subexpressions will almost // certainly have to be exploded in order to maintain the order of their // side effects relative to the leaping child(ren). let hasLeapingChildren = meta.containsLeap.onlyChildren(expr); // In order to save the rest of explodeExpression from a combinatorial // trainwreck of special cases, explodeViaTempVar is responsible for // deciding when a subexpression needs to be "exploded," which is my // very technical term for emitting the subexpression as an assignment // to a temporary variable and the substituting the temporary variable // for the original subexpression. Think of exploded view diagrams, not // Michael Bay movies. The point of exploding subexpressions is to // control the precise order in which the generated code realizes the // side effects of those subexpressions. function explodeViaTempVar(tempVar, childPath, ignoreChildResult) { assert.ok( !ignoreChildResult || !tempVar, "Ignoring the result of a child expression but forcing it to " + "be assigned to a temporary variable?" ); let result = self.explodeExpression(childPath, ignoreChildResult); if (ignoreChildResult) { // Side effects already emitted above. } else if (tempVar || (hasLeapingChildren && !t.isLiteral(result))) { // If tempVar was provided, then the result will always be assigned // to it, even if the result does not otherwise need to be assigned // to a temporary variable. When no tempVar is provided, we have // the flexibility to decide whether a temporary variable is really // necessary. Unfortunately, in general, a temporary variable is // required whenever any child contains a yield expression, since it // is difficult to prove (at all, let alone efficiently) whether // this result would evaluate to the same value before and after the // yield (see #206). One narrow case where we can prove it doesn't // matter (and thus we do not need a temporary variable) is when the // result in question is a Literal value. result = self.emitAssign( tempVar || self.makeTempVar(), result ); } return result; } // If ignoreResult is true, then we must take full responsibility for // emitting the expression with all its side effects, and we should not // return a result. switch (expr.type) { case "MemberExpression": return finish(t.memberExpression( self.explodeExpression(path.get("object")), expr.computed ? explodeViaTempVar(null, path.get("property")) : expr.property, expr.computed )); case "CallExpression": let calleePath = path.get("callee"); let argsPath = path.get("arguments"); let newCallee; let newArgs = []; let hasLeapingArgs = false; argsPath.forEach(function(argPath) { hasLeapingArgs = hasLeapingArgs || meta.containsLeap(argPath.node); }); if (t.isMemberExpression(calleePath.node)) { if (hasLeapingArgs) { // If the arguments of the CallExpression contained any yield // expressions, then we need to be sure to evaluate the callee // before evaluating the arguments, but if the callee was a member // expression, then we must be careful that the object of the // member expression still gets bound to `this` for the call. let newObject = explodeViaTempVar( // Assign the exploded callee.object expression to a temporary // variable so that we can use it twice without reevaluating it. self.makeTempVar(), calleePath.get("object") ); let newProperty = calleePath.node.computed ? explodeViaTempVar(null, calleePath.get("property")) : calleePath.node.property; newArgs.unshift(newObject); newCallee = t.memberExpression( t.memberExpression( newObject, newProperty, calleePath.node.computed ), t.identifier("call"), false ); } else { newCallee = self.explodeExpression(calleePath); } } else { newCallee = self.explodeExpression(calleePath); if (t.isMemberExpression(newCallee)) { // If the callee was not previously a MemberExpression, then the // CallExpression was "unqualified," meaning its `this` object // should be the global object. If the exploded expression has // become a MemberExpression (e.g. a context property, probably a // temporary variable), then we need to force it to be unqualified // by using the (0, object.property)(...) trick; otherwise, it // will receive the object of the MemberExpression as its `this` // object. newCallee = t.sequenceExpression([ t.numbericLiteral(0), newCallee ]); } } argsPath.forEach(function(argPath) { newArgs.push(explodeViaTempVar(null, argPath)); }); return finish(t.callExpression( newCallee, newArgs )); case "NewExpression": return finish(t.newExpression( explodeViaTempVar(null, path.get("callee")), path.get("arguments").map(function(argPath) { return explodeViaTempVar(null, argPath); }) )); case "ObjectExpression": return finish(t.objectExpression( path.get("properties").map(function(propPath) { if (propPath.isObjectProperty()) { return t.objectProperty( propPath.node.key, explodeViaTempVar(null, propPath.get("value")), propPath.node.computed ); } else { return propPath.node; } }) )); case "ArrayExpression": return finish(t.arrayExpression( path.get("elements").map(function(elemPath) { return explodeViaTempVar(null, elemPath); }) )); case "SequenceExpression": let lastIndex = expr.expressions.length - 1; path.get("expressions").forEach(function(exprPath) { if (exprPath.key === lastIndex) { result = self.explodeExpression(exprPath, ignoreResult); } else { self.explodeExpression(exprPath, true); } }); return result; case "LogicalExpression": after = loc(); if (!ignoreResult) { result = self.makeTempVar(); } let left = explodeViaTempVar(result, path.get("left")); if (expr.operator === "&&") { self.jumpIfNot(left, after); } else { assert.strictEqual(expr.operator, "||"); self.jumpIf(left, after); } explodeViaTempVar(result, path.get("right"), ignoreResult); self.mark(after); return result; case "ConditionalExpression": let elseLoc = loc(); after = loc(); let test = self.explodeExpression(path.get("test")); self.jumpIfNot(test, elseLoc); if (!ignoreResult) { result = self.makeTempVar(); } explodeViaTempVar(result, path.get("consequent"), ignoreResult); self.jump(after); self.mark(elseLoc); explodeViaTempVar(result, path.get("alternate"), ignoreResult); self.mark(after); return result; case "UnaryExpression": return finish(t.unaryExpression( expr.operator, // Can't (and don't need to) break up the syntax of the argument. // Think about delete a[b]. self.explodeExpression(path.get("argument")), !!expr.prefix )); case "BinaryExpression": return finish(t.binaryExpression( expr.operator, explodeViaTempVar(null, path.get("left")), explodeViaTempVar(null, path.get("right")) )); case "AssignmentExpression": return finish(t.assignmentExpression( expr.operator, self.explodeExpression(path.get("left")), self.explodeExpression(path.get("right")) )); case "UpdateExpression": return finish(t.updateExpression( expr.operator, self.explodeExpression(path.get("argument")), expr.prefix )); case "YieldExpression": after = loc(); let arg = expr.argument && self.explodeExpression(path.get("argument")); if (arg && expr.delegate) { let result = self.makeTempVar(); self.emit(t.returnStatement(t.callExpression( self.contextProperty("delegateYield"), [ arg, t.stringLiteral(result.property.name), after ] ))); self.mark(after); return result; } self.emitAssign(self.contextProperty("next"), after); self.emit(t.returnStatement(arg || null)); self.mark(after); return self.contextProperty("sent"); default: throw new Error( "unknown Expression of type " + JSON.stringify(expr.type)); } };
compile: function(){ var ast = []; if (this.pp) { ast.push(t.variableDeclaration('var', [t.variableDeclarator(t.identifier('pug_indent'), t.arrayExpression())])); } push.apply(ast, this.visit(this.node)); if (!this.dynamicMixins) { // if there are no dynamic mixins we can remove any un-used mixins var mixinNames = Object.keys(this.mixins); for (var i = 0; i < mixinNames.length; i++) { var mixin = this.mixins[mixinNames[i]]; if (!mixin.used) { for (var x = 0; x < mixin.instances.length; x++) { mixin.instances[x].stmt.type = "EmptyStatement"; delete mixin.instances[x].stmt.expression; } } } } if (this.options.self) { ast = [ t.variableDeclaration('var', [ t.variableDeclarator(t.identifier('self'), t.logicalExpression('||', t.identifier('locals'), t.objectExpression([]))) ]) ].concat(ast); } else { ast = [t.withStatement(t.identifier('locals'), t.blockStatement(ast))] } if (this.debug) { if (this.options.includeSources) { ast.unshift(t.variableDeclaration('var', [ t.variableDeclarator(t.identifier('pug_debug_sources'), this.parseExpr(stringify(this.options.includeSources))) ])) } var rethrowArgs = [ t.identifier('err'), t.identifier('pug_debug_filename'), t.identifier('pug_debug_line') ] if (this.options.includeSources) { rethrowArgs.push(t.memberExpression(t.identifier('pug_debug_sources'), t.identifier('pug_debug_filename'), true)) } ast = [ t.variableDeclaration('var', [ t.variableDeclarator(t.identifier('pug_debug_filename'), null), t.variableDeclarator(t.identifier('pug_debug_line'), null) ]), t.tryStatement( t.blockStatement(ast), t.catchClause( t.identifier('err'), t.blockStatement([t.expressionStatement(t.callExpression( (this.inlineRuntimeFunctions ? t.identifier('pug_rethrow') : t.memberExpression(t.identifier('pug'), t.identifier('rethrow'))), rethrowArgs ))]) ) ) ] } ast = t.functionDeclaration( t.identifier(this.options.templateName || 'template'), this.templateVars.map(function(v) { return t.identifier(v)}), t.blockStatement([this.ast_variableDeclaration()].concat(ast, this.ast_return())) ) var plugins = [ babelPluginPugConcat ]; if (!this.options.self) { let globals = this.options.globals ? this.options.globals.concat(INTERNAL_VARIABLES) : INTERNAL_VARIABLES; globals.concat(this.runtimeFunctionsUsed.map(function (name) { return 'pug_' + name; })); plugins.push([babelPluginTransformWith, { exclude: globals }]); } var file = babylon.parse(''); file.program.body = [ast]; var w = babel.transformFromAst(file, null, { code: false, plugins: plugins }); return buildRuntime(this.runtimeFunctionsUsed) + gen.default(w.ast).code; },
export let property = opts => { const tmpl = template(` module.exports = function (parsed) { var valid = true; var count = 0; parsed.walk(function (node) { WORD STRING SEPARATOR }); return count > COUNT ? false : valid; } `); const properties = template(`module.exports.properties = EXPORTS;`)({ EXPORTS: t.arrayExpression(opts.properties.map(toStringLiteral)) }); let config = ['SEPARATOR', 'STRING', 'WORD'].reduce((list, key) => { list[key] = t.emptyStatement(); return list; }, {}); config.COUNT = t.numericLiteral(opts.count); let conditions = []; let dependencies = []; if (opts.values && opts.values.length) { if (opts.values.length === 1) { conditions.push(template(`node.value !== "${opts.values[0]}"`)().expression); } else { conditions.push(template(`!~VALUES.indexOf(node.value)`)({ VALUES: t.arrayExpression(opts.values.map(toStringLiteral)) }).expression); } } ['length', 'integer', 'percentage', 'number', 'time'].forEach(type => { if (!opts[type]) { return; } const camel = 'is' + type[0].toUpperCase() + type.slice(1, type.length); conditions.push(template(`!${camel}(node.value)`)().expression); dependencies.push(requireModule({ identifier: camel, module: `../../validators/${camel}` })); }); if (conditions.length) { config.WORD = template(`if (node.type === 'word') { inject; count++; }`)({ inject: template('if (inject) { valid = false; return false; }')({ inject: generateConditions.apply(null, conditions) }) }); } if (opts.string) { config.STRING = template(`if (node.type === 'string') { count++; }`)(); } if (opts.repeat && opts.repeat.separator) { config.SEPARATOR = template(`if (node.type === 'div' && node.value === "${opts.repeat.separator}") { count --; }`)(); } let program = t.program([ tmpl(config), properties ]); traverse(program, { noScope: true, EmptyStatement: function (path) { path.remove(); } }); return warning() + dependencies.join('') + generate(program).code; };
function makePropType(data) { const method = data.type; let reactNode = t.callExpression(t.identifier('require'), [makeLiteral('react')]); let node = t.memberExpression(reactNode, t.identifier('PropTypes')); let isRequired = true; if (method === 'any' || method === 'string' || method === 'number' || method === 'bool' || method === 'object' || method === 'array' || method === 'func') { node = t.memberExpression(node, t.identifier(method)); } else if (method === 'raw') { node = t.identifier(data.value); isRequired = false; } else if (method === 'shape') { const shapeObjectProperties = (data.properties || {}).map(({key, value}) => { return t.objectProperty( t.identifier(key), makePropType(value) ); }); const shapeObjectLiteral = t.objectExpression(shapeObjectProperties); node = t.callExpression( t.memberExpression(node, t.identifier('shape')), [shapeObjectLiteral] ); } else if (method === 'arrayOf') { node = t.callExpression( t.memberExpression(node, t.identifier('arrayOf')), [makePropType(data.of)] ); } else if (method === 'oneOf') { node = t.callExpression( t.memberExpression(node, t.identifier('oneOf')), [t.arrayExpression(data.options.map(makeLiteral))] ); } else if (method === 'oneOfType') { node = t.callExpression( t.memberExpression(node, t.identifier('oneOfType')), [t.arrayExpression(data.options.map(makePropType))] ); } else if (method === 'void') { node = dontSetTemplate().expression; } else if (method === 'instanceOf') { node = t.callExpression( t.memberExpression(node, t.identifier('instanceOf')), [t.identifier(data.of)] ) } else { $debug('Unknown node ' + JSON.stringify(data, null, 2)); throw new Error(`${PLUGIN_NAME} processing error: This is an internal error that should never happen. ` + `Report it immediately with the source file and babel config. Data: ${data}`); } if (isRequired && data.isRequired && method !== 'void') { node = t.memberExpression(node, t.identifier('isRequired')); } return node; }
module.exports = function addTestcheck(path, state, fnString) { const params = state.get('paramTypes'); // set by decypherParamTypes.js // creates `testcheck.check` const check = t.memberExpression( t.identifier('testcheck'), t.identifier('check') ); // creates `testcheck.property` const property = t.memberExpression( t.identifier('testcheck'), t.identifier('property') ); // creates `testcheckResults.push` const resultsPush = t.memberExpression( t.identifier('testcheckResults'), t.identifier('push') ); const testcheckArgs = params.map(p => createGenArgument(p.type)); // creates // ```js // testcheck.check( // testcheck.property( // [args], // function() { ... } // ) // ); // ``` const fn = t.callExpression(check, [ t.callExpression(property, [ t.arrayExpression(testcheckArgs), t.identifier(fnString), ]), ]); // creates // ```js // { // name: '', // results: fn() // } const resultObject = t.objectExpression( [t.objectProperty( t.identifier('name'), t.stringLiteral(path.node.id.name) ), t.objectProperty( t.identifier('results'), fn )] ); const allTogetherNow = t.callExpression( resultsPush, [resultObject] ); path.insertAfter(allTogetherNow); };