import * as AST from '../ast'; import Env, { EnvError } from '../env'; import Token from '../token'; interface Expansion { rules: (String | EnvError)[]; children: (String | EnvError)[]; } export class Mixin { public name: Token; public parameters: AST.Identifier[]; public children: AST.Child[]; public constructor( name: Token, parameters: AST.Identifier[], children: AST.Child[] ) { this.name = name; this.parameters = parameters; this.children = children; } public compile(env: Env, _opts: AST.Opts) { env.set(this.name.value, this); return ''; } public expand( env: Env, opts: AST.Opts, parents: AST.Selector[], args: AST.Node[] ): Expansion | EnvError { if (this.parameters.length !== args.length) { return new EnvError( this.name.line, `Expected ${this.parameters.length} arguments but received ${ args.length }` ); } const mixinEnv = new Env(env); this.parameters.forEach((param, index) => { mixinEnv.set(param.name.value, args[index]); }); const rules = this.children .filter((child: AST.Node): child is AST.Rule => child instanceof AST.Rule) .map((child: AST.Rule) => child.compile(mixinEnv, opts)); const children = this.children .filter( (child: AST.Node): child is AST.RuleSet => child instanceof AST.RuleSet ) .map((child: AST.RuleSet) => { child.selectors.forEach((sel) => (sel.parents = parents)); return child.compile(mixinEnv, opts); }); return { rules, children }; } }