Added logging, changed some directory structure

This commit is contained in:
2018-01-13 21:33:40 -05:00
parent f079a5f067
commit 8e72ffb917
73656 changed files with 35284 additions and 53718 deletions

View File

@@ -0,0 +1,23 @@
var List = require('./list');
module.exports = function clone(node) {
var result = {};
for (var key in node) {
var value = node[key];
if (value) {
if (Array.isArray(value)) {
value = value.slice(0);
} else if (value instanceof List) {
value = new List(value.map(clone));
} else if (value.constructor === Object) {
value = clone(value);
}
}
result[key] = value;
}
return result;
};

View File

@@ -0,0 +1,389 @@
//
// item item item item
// /------\ /------\ /------\ /------\
// | data | | data | | data | | data |
// null <--+-prev |<---+-prev |<---+-prev |<---+-prev |
// | next-+--->| next-+--->| next-+--->| next-+--> null
// \------/ \------/ \------/ \------/
// ^ ^
// | list |
// | /------\ |
// \--------------+-head | |
// | tail-+--------------/
// \------/
//
function createItem(data) {
return {
data: data,
next: null,
prev: null
};
}
var List = function(values) {
this.cursor = null;
this.head = null;
this.tail = null;
if (Array.isArray(values)) {
var cursor = null;
for (var i = 0; i < values.length; i++) {
var item = createItem(values[i]);
if (cursor !== null) {
cursor.next = item;
} else {
this.head = item;
}
item.prev = cursor;
cursor = item;
}
this.tail = cursor;
}
};
Object.defineProperty(List.prototype, 'size', {
get: function() {
var size = 0;
var cursor = this.head;
while (cursor) {
size++;
cursor = cursor.next;
}
return size;
}
});
List.createItem = createItem;
List.prototype.createItem = createItem;
List.prototype.toArray = function() {
var cursor = this.head;
var result = [];
while (cursor) {
result.push(cursor.data);
cursor = cursor.next;
}
return result;
};
List.prototype.toJSON = function() {
return this.toArray();
};
List.prototype.isEmpty = function() {
return this.head === null;
};
List.prototype.first = function() {
return this.head && this.head.data;
};
List.prototype.last = function() {
return this.tail && this.tail.data;
};
List.prototype.each = function(fn, context) {
var item;
var cursor = {
prev: null,
next: this.head,
cursor: this.cursor
};
if (context === undefined) {
context = this;
}
// push cursor
this.cursor = cursor;
while (cursor.next !== null) {
item = cursor.next;
cursor.next = item.next;
fn.call(context, item.data, item, this);
}
// pop cursor
this.cursor = this.cursor.cursor;
};
List.prototype.eachRight = function(fn, context) {
var item;
var cursor = {
prev: this.tail,
next: null,
cursor: this.cursor
};
if (context === undefined) {
context = this;
}
// push cursor
this.cursor = cursor;
while (cursor.prev !== null) {
item = cursor.prev;
cursor.prev = item.prev;
fn.call(context, item.data, item, this);
}
// pop cursor
this.cursor = this.cursor.cursor;
};
List.prototype.nextUntil = function(start, fn, context) {
if (start === null) {
return;
}
var item;
var cursor = {
prev: null,
next: start,
cursor: this.cursor
};
if (context === undefined) {
context = this;
}
// push cursor
this.cursor = cursor;
while (cursor.next !== null) {
item = cursor.next;
cursor.next = item.next;
if (fn.call(context, item.data, item, this)) {
break;
}
}
// pop cursor
this.cursor = this.cursor.cursor;
};
List.prototype.prevUntil = function(start, fn, context) {
if (start === null) {
return;
}
var item;
var cursor = {
prev: start,
next: null,
cursor: this.cursor
};
if (context === undefined) {
context = this;
}
// push cursor
this.cursor = cursor;
while (cursor.prev !== null) {
item = cursor.prev;
cursor.prev = item.prev;
if (fn.call(context, item.data, item, this)) {
break;
}
}
// pop cursor
this.cursor = this.cursor.cursor;
};
List.prototype.some = function(fn, context) {
var cursor = this.head;
if (context === undefined) {
context = this;
}
while (cursor !== null) {
if (fn.call(context, cursor.data, cursor, this)) {
return true;
}
cursor = cursor.next;
}
return false;
};
List.prototype.map = function(fn, context) {
var result = [];
var cursor = this.head;
if (context === undefined) {
context = this;
}
while (cursor !== null) {
result.push(fn.call(context, cursor.data, cursor, this));
cursor = cursor.next;
}
return result;
};
List.prototype.copy = function() {
var result = new List();
var cursor = this.head;
while (cursor !== null) {
result.insert(createItem(cursor.data));
cursor = cursor.next;
}
return result;
};
List.prototype.updateCursors = function(prevOld, prevNew, nextOld, nextNew) {
var cursor = this.cursor;
while (cursor !== null) {
if (prevNew === true || cursor.prev === prevOld) {
cursor.prev = prevNew;
}
if (nextNew === true || cursor.next === nextOld) {
cursor.next = nextNew;
}
cursor = cursor.cursor;
}
};
List.prototype.insert = function(item, before) {
if (before !== undefined && before !== null) {
// prev before
// ^
// item
this.updateCursors(before.prev, item, before, item);
if (before.prev === null) {
// insert to the beginning of list
if (this.head !== before) {
throw new Error('before doesn\'t below to list');
}
// since head points to before therefore list doesn't empty
// no need to check tail
this.head = item;
before.prev = item;
item.next = before;
this.updateCursors(null, item);
} else {
// insert between two items
before.prev.next = item;
item.prev = before.prev;
before.prev = item;
item.next = before;
}
} else {
// tail
// ^
// item
this.updateCursors(this.tail, item, null, item);
// insert to end of the list
if (this.tail !== null) {
// if list has a tail, then it also has a head, but head doesn't change
// last item -> new item
this.tail.next = item;
// last item <- new item
item.prev = this.tail;
} else {
// if list has no a tail, then it also has no a head
// in this case points head to new item
this.head = item;
}
// tail always start point to new item
this.tail = item;
}
};
List.prototype.remove = function(item) {
// item
// ^
// prev next
this.updateCursors(item, item.prev, item, item.next);
if (item.prev !== null) {
item.prev.next = item.next;
} else {
if (this.head !== item) {
throw new Error('item doesn\'t below to list');
}
this.head = item.next;
}
if (item.next !== null) {
item.next.prev = item.prev;
} else {
if (this.tail !== item) {
throw new Error('item doesn\'t below to list');
}
this.tail = item.prev;
}
item.prev = null;
item.next = null;
return item;
};
List.prototype.appendList = function(list) {
// ignore empty lists
if (list.head === null) {
return;
}
this.updateCursors(this.tail, list.tail, null, list.head);
// insert to end of the list
if (this.tail !== null) {
// if destination list has a tail, then it also has a head,
// but head doesn't change
// dest tail -> source head
this.tail.next = list.head;
// dest tail <- source head
list.head.prev = this.tail;
} else {
// if list has no a tail, then it also has no a head
// in this case points head to new item
this.head = list.head;
}
// tail always start point to new item
this.tail = list.tail;
list.head = null;
list.tail = null;
};
module.exports = List;

View File

@@ -0,0 +1,73 @@
var hasOwnProperty = Object.prototype.hasOwnProperty;
var knownKeywords = Object.create(null);
var knownProperties = Object.create(null);
function getVendorPrefix(string) {
if (string[0] === '-') {
// skip 2 chars to avoid wrong match with variables names
var secondDashIndex = string.indexOf('-', 2);
if (secondDashIndex !== -1) {
return string.substr(0, secondDashIndex + 1);
}
}
return '';
}
function getKeywordInfo(keyword) {
if (hasOwnProperty.call(knownKeywords, keyword)) {
return knownKeywords[keyword];
}
var lowerCaseKeyword = keyword.toLowerCase();
var vendor = getVendorPrefix(lowerCaseKeyword);
var name = lowerCaseKeyword;
if (vendor) {
name = name.substr(vendor.length);
}
return knownKeywords[keyword] = Object.freeze({
vendor: vendor,
prefix: vendor,
name: name
});
}
function getPropertyInfo(property) {
if (hasOwnProperty.call(knownProperties, property)) {
return knownProperties[property];
}
var lowerCaseProperty = property.toLowerCase();
var hack = lowerCaseProperty[0];
if (hack === '*' || hack === '_' || hack === '$') {
lowerCaseProperty = lowerCaseProperty.substr(1);
} else if (hack === '/' && property[1] === '/') {
hack = '//';
lowerCaseProperty = lowerCaseProperty.substr(2);
} else {
hack = '';
}
var vendor = getVendorPrefix(lowerCaseProperty);
var name = lowerCaseProperty;
if (vendor) {
name = name.substr(vendor.length);
}
return knownProperties[property] = Object.freeze({
hack: hack,
vendor: vendor,
prefix: hack + vendor,
name: name
});
}
module.exports = {
keyword: getKeywordInfo,
property: getPropertyInfo
};

View File

@@ -0,0 +1,178 @@
function each(list) {
if (list.head === null) {
return '';
}
if (list.head === list.tail) {
return translate(list.head.data);
}
return list.map(translate).join('');
}
function eachDelim(list, delimeter) {
if (list.head === null) {
return '';
}
if (list.head === list.tail) {
return translate(list.head.data);
}
return list.map(translate).join(delimeter);
}
function translate(node) {
switch (node.type) {
case 'StyleSheet':
return each(node.rules);
case 'Atrule':
var nodes = ['@', node.name];
if (node.expression && !node.expression.sequence.isEmpty()) {
nodes.push(' ', translate(node.expression));
}
if (node.block) {
nodes.push('{', translate(node.block), '}');
} else {
nodes.push(';');
}
return nodes.join('');
case 'Ruleset':
return translate(node.selector) + '{' + translate(node.block) + '}';
case 'Selector':
return eachDelim(node.selectors, ',');
case 'SimpleSelector':
var nodes = node.sequence.map(function(node) {
// add extra spaces around /deep/ combinator since comment beginning/ending may to be produced
if (node.type === 'Combinator' && node.name === '/deep/') {
return ' ' + translate(node) + ' ';
}
return translate(node);
});
return nodes.join('');
case 'Block':
return eachDelim(node.declarations, ';');
case 'Declaration':
return translate(node.property) + ':' + translate(node.value);
case 'Property':
return node.name;
case 'Value':
return node.important
? each(node.sequence) + '!important'
: each(node.sequence);
case 'Attribute':
var result = translate(node.name);
var flagsPrefix = ' ';
if (node.operator !== null) {
result += node.operator;
if (node.value !== null) {
result += translate(node.value);
// space between string and flags is not required
if (node.value.type === 'String') {
flagsPrefix = '';
}
}
}
if (node.flags !== null) {
result += flagsPrefix + node.flags;
}
return '[' + result + ']';
case 'FunctionalPseudo':
return ':' + node.name + '(' + eachDelim(node.arguments, ',') + ')';
case 'Function':
return node.name + '(' + eachDelim(node.arguments, ',') + ')';
case 'Negation':
return ':not(' + eachDelim(node.sequence, ',') + ')';
case 'Braces':
return node.open + each(node.sequence) + node.close;
case 'Argument':
case 'AtruleExpression':
return each(node.sequence);
case 'Url':
return 'url(' + translate(node.value) + ')';
case 'Progid':
return translate(node.value);
case 'Combinator':
return node.name;
case 'Identifier':
return node.name;
case 'PseudoClass':
return ':' + node.name;
case 'PseudoElement':
return '::' + node.name;
case 'Class':
return '.' + node.name;
case 'Id':
return '#' + node.name;
case 'Hash':
return '#' + node.value;
case 'Dimension':
return node.value + node.unit;
case 'Nth':
return node.value;
case 'Number':
return node.value;
case 'String':
return node.value;
case 'Operator':
return node.value;
case 'Raw':
return node.value;
case 'Unknown':
return node.value;
case 'Percentage':
return node.value + '%';
case 'Space':
return ' ';
case 'Comment':
return '/*' + node.value + '*/';
default:
throw new Error('Unknown node type: ' + node.type);
}
}
module.exports = translate;

View File

@@ -0,0 +1,291 @@
var SourceMapGenerator = require('source-map').SourceMapGenerator;
var SourceNode = require('source-map').SourceNode;
// Our own implementation of SourceNode#toStringWithSourceMap,
// since SourceNode doesn't allow multiple references to original source.
// Also, as we know structure of result we could be optimize generation
// (currently it's ~40% faster).
function walk(node, fn) {
for (var chunk, i = 0; i < node.children.length; i++) {
chunk = node.children[i];
if (chunk instanceof SourceNode) {
// this is a hack, because source maps doesn't support for 1(generated):N(original)
// if (chunk.merged) {
// fn('', chunk);
// }
walk(chunk, fn);
} else {
fn(chunk, node);
}
}
}
function generateSourceMap(root) {
var map = new SourceMapGenerator();
var css = '';
var sourceMappingActive = false;
var lastOriginalLine = null;
var lastOriginalColumn = null;
var lastIndexOfNewline;
var generated = {
line: 1,
column: 0
};
var activatedMapping = {
generated: generated
};
walk(root, function(chunk, original) {
if (original.line !== null &&
original.column !== null) {
if (lastOriginalLine !== original.line ||
lastOriginalColumn !== original.column) {
map.addMapping({
source: original.source,
original: original,
generated: generated
});
}
lastOriginalLine = original.line;
lastOriginalColumn = original.column;
sourceMappingActive = true;
} else if (sourceMappingActive) {
map.addMapping(activatedMapping);
sourceMappingActive = false;
}
css += chunk;
lastIndexOfNewline = chunk.lastIndexOf('\n');
if (lastIndexOfNewline !== -1) {
generated.line += chunk.match(/\n/g).length;
generated.column = chunk.length - lastIndexOfNewline - 1;
} else {
generated.column += chunk.length;
}
});
return {
css: css,
map: map
};
}
function createAnonymousSourceNode(children) {
return new SourceNode(
null,
null,
null,
children
);
}
function createSourceNode(info, children) {
if (info.primary) {
// special marker node to add several references to original
// var merged = createSourceNode(info.merged, []);
// merged.merged = true;
// children.unshift(merged);
// use recursion, because primary can also has a primary/merged info
return createSourceNode(info.primary, children);
}
return new SourceNode(
info.line,
info.column - 1,
info.source,
children
);
}
function each(list) {
if (list.head === null) {
return '';
}
if (list.head === list.tail) {
return translate(list.head.data);
}
return list.map(translate).join('');
}
function eachDelim(list, delimeter) {
if (list.head === null) {
return '';
}
if (list.head === list.tail) {
return translate(list.head.data);
}
return list.map(translate).join(delimeter);
}
function translate(node) {
switch (node.type) {
case 'StyleSheet':
return createAnonymousSourceNode(node.rules.map(translate));
case 'Atrule':
var nodes = ['@', node.name];
if (node.expression && !node.expression.sequence.isEmpty()) {
nodes.push(' ', translate(node.expression));
}
if (node.block) {
nodes.push('{', translate(node.block), '}');
} else {
nodes.push(';');
}
return createSourceNode(node.info, nodes);
case 'Ruleset':
return createAnonymousSourceNode([
translate(node.selector), '{', translate(node.block), '}'
]);
case 'Selector':
return createAnonymousSourceNode(node.selectors.map(translate)).join(',');
case 'SimpleSelector':
var nodes = node.sequence.map(function(node) {
// add extra spaces around /deep/ combinator since comment beginning/ending may to be produced
if (node.type === 'Combinator' && node.name === '/deep/') {
return ' ' + translate(node) + ' ';
}
return translate(node);
});
return createSourceNode(node.info, nodes);
case 'Block':
return createAnonymousSourceNode(node.declarations.map(translate)).join(';');
case 'Declaration':
return createSourceNode(
node.info,
[translate(node.property), ':', translate(node.value)]
);
case 'Property':
return node.name;
case 'Value':
return node.important
? each(node.sequence) + '!important'
: each(node.sequence);
case 'Attribute':
var result = translate(node.name);
var flagsPrefix = ' ';
if (node.operator !== null) {
result += node.operator;
if (node.value !== null) {
result += translate(node.value);
// space between string and flags is not required
if (node.value.type === 'String') {
flagsPrefix = '';
}
}
}
if (node.flags !== null) {
result += flagsPrefix + node.flags;
}
return '[' + result + ']';
case 'FunctionalPseudo':
return ':' + node.name + '(' + eachDelim(node.arguments, ',') + ')';
case 'Function':
return node.name + '(' + eachDelim(node.arguments, ',') + ')';
case 'Negation':
return ':not(' + eachDelim(node.sequence, ',') + ')';
case 'Braces':
return node.open + each(node.sequence) + node.close;
case 'Argument':
case 'AtruleExpression':
return each(node.sequence);
case 'Url':
return 'url(' + translate(node.value) + ')';
case 'Progid':
return translate(node.value);
case 'Combinator':
return node.name;
case 'Identifier':
return node.name;
case 'PseudoClass':
return ':' + node.name;
case 'PseudoElement':
return '::' + node.name;
case 'Class':
return '.' + node.name;
case 'Id':
return '#' + node.name;
case 'Hash':
return '#' + node.value;
case 'Dimension':
return node.value + node.unit;
case 'Nth':
return node.value;
case 'Number':
return node.value;
case 'String':
return node.value;
case 'Operator':
return node.value;
case 'Raw':
return node.value;
case 'Unknown':
return node.value;
case 'Percentage':
return node.value + '%';
case 'Space':
return ' ';
case 'Comment':
return '/*' + node.value + '*/';
default:
throw new Error('Unknown node type: ' + node.type);
}
}
module.exports = function(node) {
return generateSourceMap(
createAnonymousSourceNode(translate(node))
);
};

View File

@@ -0,0 +1,189 @@
function walkRules(node, item, list) {
switch (node.type) {
case 'StyleSheet':
var oldStylesheet = this.stylesheet;
this.stylesheet = node;
node.rules.each(walkRules, this);
this.stylesheet = oldStylesheet;
break;
case 'Atrule':
if (node.block !== null) {
walkRules.call(this, node.block);
}
this.fn(node, item, list);
break;
case 'Ruleset':
this.fn(node, item, list);
break;
}
}
function walkRulesRight(node, item, list) {
switch (node.type) {
case 'StyleSheet':
var oldStylesheet = this.stylesheet;
this.stylesheet = node;
node.rules.eachRight(walkRulesRight, this);
this.stylesheet = oldStylesheet;
break;
case 'Atrule':
if (node.block !== null) {
walkRulesRight.call(this, node.block);
}
this.fn(node, item, list);
break;
case 'Ruleset':
this.fn(node, item, list);
break;
}
}
function walkAll(node, item, list) {
switch (node.type) {
case 'StyleSheet':
var oldStylesheet = this.stylesheet;
this.stylesheet = node;
node.rules.each(walkAll, this);
this.stylesheet = oldStylesheet;
break;
case 'Atrule':
if (node.expression !== null) {
walkAll.call(this, node.expression);
}
if (node.block !== null) {
walkAll.call(this, node.block);
}
break;
case 'Ruleset':
this.ruleset = node;
if (node.selector !== null) {
walkAll.call(this, node.selector);
}
walkAll.call(this, node.block);
this.ruleset = null;
break;
case 'Selector':
var oldSelector = this.selector;
this.selector = node;
node.selectors.each(walkAll, this);
this.selector = oldSelector;
break;
case 'Block':
node.declarations.each(walkAll, this);
break;
case 'Declaration':
this.declaration = node;
walkAll.call(this, node.property);
walkAll.call(this, node.value);
this.declaration = null;
break;
case 'Attribute':
walkAll.call(this, node.name);
if (node.value !== null) {
walkAll.call(this, node.value);
}
break;
case 'FunctionalPseudo':
case 'Function':
this['function'] = node;
node.arguments.each(walkAll, this);
this['function'] = null;
break;
case 'AtruleExpression':
this.atruleExpression = node;
node.sequence.each(walkAll, this);
this.atruleExpression = null;
break;
case 'Value':
case 'Argument':
case 'SimpleSelector':
case 'Braces':
case 'Negation':
node.sequence.each(walkAll, this);
break;
case 'Url':
case 'Progid':
walkAll.call(this, node.value);
break;
// nothig to do with
// case 'Property':
// case 'Combinator':
// case 'Dimension':
// case 'Hash':
// case 'Identifier':
// case 'Nth':
// case 'Class':
// case 'Id':
// case 'Percentage':
// case 'PseudoClass':
// case 'PseudoElement':
// case 'Space':
// case 'Number':
// case 'String':
// case 'Operator':
// case 'Raw':
}
this.fn(node, item, list);
}
function createContext(root, fn) {
var context = {
fn: fn,
root: root,
stylesheet: null,
atruleExpression: null,
ruleset: null,
selector: null,
declaration: null,
function: null
};
return context;
}
module.exports = {
all: function(root, fn) {
walkAll.call(createContext(root, fn), root);
},
rules: function(root, fn) {
walkRules.call(createContext(root, fn), root);
},
rulesRight: function(root, fn) {
walkRulesRight.call(createContext(root, fn), root);
}
};