UNPKG

opencolor

Version:

A collection of functions to parse Open Color files, construct them via code and write them

267 lines (237 loc) 8.77 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; }; exports.default = parse; var _entry = require('./entry'); var _entry2 = _interopRequireDefault(_entry); var _color_value = require('./color_value'); var _color_value2 = _interopRequireDefault(_color_value); var _reference = require('./reference'); var _reference2 = _interopRequireDefault(_reference); var _parser_error = require('./parser_error'); var _parser_error2 = _interopRequireDefault(_parser_error); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /** @ignore */ function parse(input) { var tokenized = tokenize(input.toString()); var transformed = transform(tokenized); var adjusted = adjustTypes(transformed); var metaadjusted = normalizeMetadata(adjusted); var objectified = objectify(metaadjusted); return objectified; } function tokenize(input) { var output = []; var lines = input.split('\n'); lines.forEach(function (line) { line = line.replace(/\/\/.*$/, ''); // remove comments var tokens = line.split(':').map(function (t) { return t.trim(); }); output.push({ indent: indent(line), tokens: tokens }); }); return output; } function indent(line) { var m = line.match(/^[ \t]+/); if (!m) { return 0; } return m[0].length; } function makeArrayUnique(inp) { // http://stackoverflow.com/questions/1960473/unique-values-in-an-array var a = []; for (var i = 0, l = inp.length; i < l; i++) { if (a.indexOf(inp[i]) === -1) { a.push(inp[i]); } } return a; } function transform(input) { var output = { children: [], type: 'root', name: 'root', parent: null, line: 0 }; var currentIndent = input[0].indent; var currentGroup = output; input.forEach(function (line, i) { if (line.tokens.length === 1 && line.tokens[0] === '') { return; } // remove empty lines from the stream) if (line.indent > currentIndent) { currentGroup = currentGroup.children[currentGroup.children.length - 1]; } else if (line.indent < currentIndent) { currentGroup = currentGroup.parent; } currentIndent = line.indent; if (line.tokens.length === 2 && line.tokens[1] === '') { // a Group if (line.tokens[0].match(/\//)) { // Metadata currentGroup.children.push({ type: 'metagroup', name: line.tokens[0], parent: currentGroup, children: [], line: i }); } else { currentGroup.children.push({ type: 'palette', name: line.tokens[0], parent: currentGroup, children: [], line: i }); } } else if (line.tokens.length === 1) { // a color or a meta group with trailing slash if (line.tokens[0].match(/\/$/)) { currentGroup.children.push({ type: 'metagroup', name: line.tokens[0], parent: currentGroup, children: [], line: i }); } else if (line.tokens[0].match(/\//)) { throw new _parser_error2.default('A meta group must either have a trailing slash or must be closed with a colon', { line: i }); } else if (line.tokens[0].match(/^=/)) { currentGroup.children.push({ type: 'reference', value: line.tokens[0], parent: currentGroup, children: [], line: i }); } else { currentGroup.children.push({ type: 'colorvalue', value: line.tokens[0], parent: currentGroup, children: [], line: i }); } } else if (line.tokens.length === 2) { // everything else is just a kv if (line.tokens[0].match(/\//)) { currentGroup.children.push({ type: 'metavalue', name: line.tokens[0], value: line.tokens[1], parent: currentGroup, children: [], line: i }); } else { currentGroup.children.push({ type: 'value', name: line.tokens[0], value: line.tokens[1], parent: currentGroup, children: [], line: i }); } } else { // other token lengths are syntax errors throw new _parser_error2.default('Too many colons', { line: i }); } }); return output; } function adjustTypes(tree) { tree.children.forEach(function (child, i) { if (child.type === 'palette') { var childTypes = makeArrayUnique(child.children.map(function (c) { return c.type; })); if (childTypes.indexOf('colorvalue') !== -1) { if (childTypes.indexOf('palette') !== -1) { throw new _parser_error2.default('Color cannot contain both color values and a subpalette', { line: child.line }); } else if (childTypes.indexOf('value') !== -1) { throw new _parser_error2.default('Color cannot contain both color values and named colors', { line: child.line }); } child.type = 'color'; } } else if (child.type === 'value') { if (child.parent.type === 'metagroup') { child.type = 'metavalue'; checkForChildren('Metavalue', child); } else { if (child.value.match(/^=/)) { child.type = 'reference'; } else { child.type = 'color'; child.children.push({ type: 'colorvalue', value: child.value, parent: child, children: [], line: child.line }); delete child.value; } } } else if (child.type === 'colorvalue') { checkForChildren('Colorvalue', child); } adjustTypes(child); }); return tree; } function checkForChildren(type, obj) { if (obj.children.length > 0) { throw new _parser_error2.default(type + ' ' + obj.name + ' can\'t have children', { line: obj.line }); } } function normalizeMetadata(tree) { tree.children.forEach(function (child, i) { normalizeMetadata(child); if (child.type === 'metavalue') { if (tree.type === 'metagroup') { if (!tree.parent['metadata']) { tree.parent.metadata = []; } var combinedName = [tree.name, child.name].join('/').replace(/\/\//g, '/'); addMetadata(tree.parent, child, combinedName); tree.children[i] = null; } else { addMetadata(tree, child); tree.children[i] = null; } } else if (child.type === 'metagroup') { if (child['metadata']) { var keys = Object.keys(child.metadata); keys.forEach(function (key) { var combinedName = [child.name, key].join('/').replace(/\/\//g, '/'); addMetadata(tree, child, combinedName); }); } tree.children[i] = null; } }); tree.children = tree.children.filter(function (a) { return !!a; }); return tree; } function addMetadata(obj, metadata) { var name = arguments.length <= 2 || arguments[2] === undefined ? null : arguments[2]; if (!obj['metadata']) { obj.metadata = []; } if (name) { metadata.name = name; } metadata.parent = obj; obj.metadata.push(metadata); } function objectify(tree) { var children = tree.children || []; children = children.map(function (c) { return objectify(c); }); if (tree.type === 'root' || tree.type === 'palette') { var _ret = function () { var palette = new _entry2.default(tree.name, children, 'Palette', { line: tree.line }); var metadata = {}; if (tree.metadata) { tree.metadata.forEach(function (md) { metadata[md.name] = md.value; }); } palette.addMetadata(metadata); return { v: palette }; }(); if ((typeof _ret === 'undefined' ? 'undefined' : _typeof(_ret)) === "object") return _ret.v; } else if (tree.type === 'color') { var _ret2 = function () { var color = new _entry2.default(tree.name, children, 'Color', { line: tree.line }); color.children = children; var metadata = {}; if (tree.metadata) { tree.metadata.forEach(function (md) { metadata[md.name] = md.value; }); } color.addMetadata(metadata); return { v: color }; }(); if ((typeof _ret2 === 'undefined' ? 'undefined' : _typeof(_ret2)) === "object") return _ret2.v; } else if (tree.type === 'colorvalue') { var cv = _color_value2.default.fromColorValue(tree.value, tree.line); return cv; } else if (tree.type === 'reference') { var _ret3 = function () { var ref = new _reference2.default(tree.name, tree.value); var metadata = {}; if (tree.metadata) { tree.metadata.forEach(function (md) { metadata[md.name] = md.value; }); } ref.addMetadata(metadata); return { v: ref }; }(); if ((typeof _ret3 === 'undefined' ? 'undefined' : _typeof(_ret3)) === "object") return _ret3.v; } }