Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

tessellate-transform

Package Overview
Dependencies
Maintainers
1
Versions
4
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

tessellate-transform - npm Package Compare versions

Comparing version 1.0.0 to 1.1.0

lib/parsers/index.js

14

CHANGELOG.md

@@ -1,6 +0,16 @@

<a name="1.0.0"></a>
# 1.0.0 (2016-11-22)
<a name="1.1.0"></a>
# 1.1.0 (2016-11-23)
<a name="tessellate-transform@1.1.0"></a>
# tessellate-transform@1.1.0 (2016-11-23)
### Features
* **transform:** Add JSON support. ([06f96a3](https://github.com/zalando-incubator/tessellate/commit/06f96a3))
<a name="tessellate-transform@1.0.0"></a>

@@ -7,0 +17,0 @@ # tessellate-transform@1.0.0 (2016-11-22)

351

dist/cli.js

@@ -65,3 +65,3 @@ module.exports =

/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 11);
/******/ return __webpack_require__(__webpack_require__.s = 14);
/******/ })

@@ -79,4 +79,4 @@ /************************************************************************/

});
exports.default = parse;
const acorn = __webpack_require__(2);
exports.default = createParser;
const acorn = __webpack_require__(5);

@@ -110,4 +110,2 @@ function processAttribute(attribute) {

}
default:
result = null;
}

@@ -117,72 +115,185 @@ return { [attribute.name.name]: result };

function processExpression(expression, opts) {
function processExpression(expression, callbacks) {
if (expression.type === 'JSXElement') {
opts.onEnter(expression.openingElement);
callbacks.onEnter(expression.openingElement);
for (let child of expression.children) {
processExpression(child, opts, expression);
processExpression(child, callbacks);
}
opts.onLeave(expression.openingElement);
callbacks.onLeave(expression.openingElement);
}
if (expression.type === 'Literal') {
opts.onLiteral(expression);
callbacks.onLiteral(expression);
}
}
function traverseAST(ast, opts) {
function traverseAST(ast, callbacks) {
for (let statement of ast.body) {
const expression = statement.expression;
processExpression(expression, opts);
processExpression(expression, callbacks);
}
}
function parse(jsx, opts) {
function parseElementType(element, typePrefix) {
if (element.name.type === 'JSXIdentifier') {
const name = element.name.name;
const isCustomClassName = /^[A-Z]/.test(name);
return isCustomClassName ? `${ typePrefix }${ name }` : name;
} else if (element.name.type === 'JSXMemberExpression') {
return `${ typePrefix }${ element.name.object.name }.${ element.name.property.name }`;
} else {
throw new Error(`Unsupported element name type ${ element.name.type }`);
}
}
function parseElementAttrs(element) {
return element.attributes.reduce((attrs, attr) => Object.assign(attrs, processAttribute(attr)), {});
}
function parseElement(element, typePrefix) {
const type = parseElementType(element, typePrefix);
const props = parseElementAttrs(element);
const jsonNode = {
type,
props: Object.keys(props).length > 0 ? props : null,
children: []
};
return jsonNode;
}
function parseLiteral(literal) {
const isNotJustWhitespace = /\S+/.test(literal.raw);
if (isNotJustWhitespace && typeof literal.value === 'string') {
return literal.value;
}
}
class StackCache {
constructor() {
this.cache = [];
this.ids = [];
this.id = 0;
}
push(item) {
this.cache[this.id] = item;
this.ids.push(this.id);
this.id += 1;
return item;
}
pop() {
return this.cache[this.ids.pop()];
}
}
function parseJSX(jsx, callbacks, opts) {
const ast = acorn.parse(jsx, { plugins: { jsx: true } });
const typePrefix = opts.typePrefix ? `${ opts.typePrefix }.` : '';
const ast = acorn.parse(jsx, { plugins: { jsx: true } });
let root = null;
const nodes = [];
const cache = new StackCache();
traverseAST(ast, {
onEnter: element => {
let type;
if (element.name.type === 'JSXIdentifier') {
const name = element.name.name;
type = /^[A-Z]/.test(name) ? `${ typePrefix }${ name }` : name;
} else {
type = `${ typePrefix }${ element.name.object.name }.${ element.name.property.name }`;
}
callbacks.onEnter(cache.push(parseElement(element, typePrefix)));
},
onLeave: element => {
callbacks.onLeave(cache.pop());
},
onLiteral: literal => {
const string = parseLiteral(literal);
if (string) callbacks.onLiteral(string);
}
});
}
const props = element.attributes.reduce((attrs, attr) => Object.assign(attrs, processAttribute(attr)), {});
const jsonNode = {
type,
props: Object.keys(props).length > 0 ? props : null,
children: []
};
function createParser(opts = {}) {
return (jsx, callbacks) => parseJSX(jsx, callbacks, opts);
}
const lastNode = nodes[nodes.length - 1];
/***/ },
/* 1 */
/***/ function(module, exports, __webpack_require__) {
if (lastNode) {
lastNode.children.push(jsonNode);
"use strict";
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = createParser;
var _jsxParser = __webpack_require__(0);
var _jsxParser2 = _interopRequireDefault(_jsxParser);
var _jsonParser = __webpack_require__(4);
var _jsonParser2 = _interopRequireDefault(_jsonParser);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function createParser(type, opts) {
switch (type) {
case '.jsx':
return (0, _jsxParser2.default)(opts);
case '.json':
return (0, _jsonParser2.default)(opts);
default:
throw new Error(`Unsupported type ${ type }`);
}
}
/***/ },
/* 2 */
/***/ function(module, exports, __webpack_require__) {
"use strict";
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = transform;
var _jsxParser = __webpack_require__(0);
var _jsxParser2 = _interopRequireDefault(_jsxParser);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function transform(content, parse) {
let root = null;
const nodes = [];
const getLastNode = () => nodes[nodes.length - 1];
const callbacks = {
onEnter: node => {
const lastNode = getLastNode();
if (typeof lastNode === 'object') {
lastNode.children.push(node);
} else {
root = jsonNode;
root = node;
}
nodes.push(jsonNode);
nodes.push(node);
},
onLeave: element => {
onLeave: node => {
nodes.pop();
},
onLiteral: literal => {
const lastNode = nodes[nodes.length - 1];
if (/\S+/.test(literal.raw)) {
lastNode.children.push(literal.value);
const lastNode = getLastNode();
if (typeof lastNode === 'object') {
lastNode.children.push(literal);
}
}
});
};
if (!root) throw new Error('Could not parse JSX.');else return root;
parse(content, callbacks);
if (!root || typeof root !== 'object') throw new Error('Could not parse JSX.');else return root;
}
/***/ },
/* 1 */
/* 3 */
/***/ function(module, exports, __webpack_require__) {

@@ -196,29 +307,115 @@

});
exports.parse = undefined;
let parse = exports.parse = (() => {
var _transform = __webpack_require__(2);
var _transform2 = _interopRequireDefault(_transform);
var _parsers = __webpack_require__(1);
var _parsers2 = _interopRequireDefault(_parsers);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
exports.default = (() => {
var _ref = _asyncToGenerator(function* (file, opts) {
switch (file.extname) {
case '.jsx':
return (0, _jsxParser2.default)(file.content, opts);
default:
throw new Error(`Unsupported file type ${ file.extname }`);
}
return (0, _transform2.default)(file.content, (0, _parsers2.default)(file.extname, opts));
});
return function parse(_x, _x2) {
function parse(_x, _x2) {
return _ref.apply(this, arguments);
};
}
return parse;
})();
var _jsxParser = __webpack_require__(0);
/***/ },
/* 4 */
/***/ function(module, exports) {
var _jsxParser2 = _interopRequireDefault(_jsxParser);
"use strict";
'use strict';
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = createParser;
const defaultJsonMap = {
typeKeys: ['type'],
childrenKeys: ['children'],
literalKeys: [],
ignoreKeys: []
};
function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
function findType(json, typeKeys) {
for (let key of typeKeys) {
if (key in json && typeof json[key] === 'string') {
return json[key];
}
}
}
function processJSONObject(json, callbacks, opts) {
const jsonMap = opts.jsonMap || defaultJsonMap;
const type = findType(json, jsonMap.typeKeys);
const props = {};
const childrenAndLiteralKeys = [];
for (let key of Object.keys(json)) {
if (jsonMap.childrenKeys.includes(key)) {
childrenAndLiteralKeys.push(key);
} else if (jsonMap.literalKeys.includes(key)) {
childrenAndLiteralKeys.push(key);
} else if (!jsonMap.ignoreKeys.includes(key) && !jsonMap.typeKeys.includes(key)) {
props[key] = json[key];
}
}
let jsonNode = null;
if (type) {
jsonNode = {
type,
props: Object.keys(props).length > 0 ? props : null,
children: []
};
}
if (jsonNode) callbacks.onEnter(jsonNode);
for (let key of childrenAndLiteralKeys) {
if (jsonMap.childrenKeys.includes(key) && jsonNode && json[key] && typeof json[key] === 'object') {
parseJSON(json[key], callbacks, opts);
} else if (jsonMap.literalKeys.includes(key) && typeof json[key] === 'string') {
callbacks.onLiteral(json[key]);
}
}
if (jsonNode) callbacks.onLeave(jsonNode);
}
function parseJSON(json, callbacks, opts) {
if (Array.isArray(json)) {
for (let object of json) {
if (object && typeof object === 'object') {
processJSONObject(object, callbacks, opts);
} else if (typeof object === 'string') {
callbacks.onLiteral(object);
}
}
} else {
processJSONObject(json, callbacks, opts);
}
}
function createParser(opts = {}) {
return (json, callbacks) => {
const object = typeof json === 'string' ? JSON.parse(json) : json;
return parseJSON(object, callbacks, opts);
};
}
/***/ },
/* 2 */
/* 5 */
/***/ function(module, exports) {

@@ -229,12 +426,12 @@

/***/ },
/* 3 */
/* 6 */
/***/ function(module, exports, __webpack_require__) {
var Promise = __webpack_require__(7)
var Promise = __webpack_require__(10)
var fs
try {
fs = __webpack_require__(9)
fs = __webpack_require__(12)
} catch(err) {
fs = __webpack_require__(8)
fs = __webpack_require__(11)
}

@@ -278,3 +475,3 @@

__webpack_require__(10).withCallback(fs, exports, api)
__webpack_require__(13).withCallback(fs, exports, api)

@@ -298,3 +495,3 @@ exports.exists = function (filename, callback) {

/***/ },
/* 4 */
/* 7 */
/***/ function(module, exports) {

@@ -325,3 +522,3 @@

/***/ },
/* 5 */
/* 8 */
/***/ function(module, exports) {

@@ -332,3 +529,3 @@

/***/ },
/* 6 */
/* 9 */
/***/ function(module, exports) {

@@ -339,3 +536,3 @@

/***/ },
/* 7 */
/* 10 */
/***/ function(module, exports) {

@@ -346,3 +543,3 @@

/***/ },
/* 8 */
/* 11 */
/***/ function(module, exports) {

@@ -353,3 +550,3 @@

/***/ },
/* 9 */
/* 12 */
/***/ function(module, exports) {

@@ -360,3 +557,3 @@

/***/ },
/* 10 */
/* 13 */
/***/ function(module, exports) {

@@ -367,3 +564,3 @@

/***/ },
/* 11 */
/* 14 */
/***/ function(module, exports, __webpack_require__) {

@@ -405,3 +602,3 @@

const options = yield parseArgs(args);
const result = yield (0, _.parse)(options.file, options.parser);
const result = yield (0, _2.default)(options.file, options.parser);
console.log(JSON.stringify(result));

@@ -418,16 +615,18 @@ });

var _path = __webpack_require__(5);
var _path = __webpack_require__(8);
var _path2 = _interopRequireDefault(_path);
var _fs = __webpack_require__(3);
var _fs = __webpack_require__(6);
var _fs2 = _interopRequireDefault(_fs);
var _yargs = __webpack_require__(6);
var _yargs = __webpack_require__(9);
var _yargs2 = _interopRequireDefault(_yargs);
var _ = __webpack_require__(1);
var _ = __webpack_require__(3);
var _2 = _interopRequireDefault(_);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

@@ -441,5 +640,5 @@

}
/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(4)(module)))
/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(7)(module)))
/***/ }
/******/ ]);

@@ -65,3 +65,3 @@ module.exports =

/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 1);
/******/ return __webpack_require__(__webpack_require__.s = 3);
/******/ })

@@ -79,4 +79,4 @@ /************************************************************************/

});
exports.default = parse;
const acorn = __webpack_require__(2);
exports.default = createParser;
const acorn = __webpack_require__(5);

@@ -110,4 +110,2 @@ function processAttribute(attribute) {

}
default:
result = null;
}

@@ -117,72 +115,185 @@ return { [attribute.name.name]: result };

function processExpression(expression, opts) {
function processExpression(expression, callbacks) {
if (expression.type === 'JSXElement') {
opts.onEnter(expression.openingElement);
callbacks.onEnter(expression.openingElement);
for (let child of expression.children) {
processExpression(child, opts, expression);
processExpression(child, callbacks);
}
opts.onLeave(expression.openingElement);
callbacks.onLeave(expression.openingElement);
}
if (expression.type === 'Literal') {
opts.onLiteral(expression);
callbacks.onLiteral(expression);
}
}
function traverseAST(ast, opts) {
function traverseAST(ast, callbacks) {
for (let statement of ast.body) {
const expression = statement.expression;
processExpression(expression, opts);
processExpression(expression, callbacks);
}
}
function parse(jsx, opts) {
function parseElementType(element, typePrefix) {
if (element.name.type === 'JSXIdentifier') {
const name = element.name.name;
const isCustomClassName = /^[A-Z]/.test(name);
return isCustomClassName ? `${ typePrefix }${ name }` : name;
} else if (element.name.type === 'JSXMemberExpression') {
return `${ typePrefix }${ element.name.object.name }.${ element.name.property.name }`;
} else {
throw new Error(`Unsupported element name type ${ element.name.type }`);
}
}
function parseElementAttrs(element) {
return element.attributes.reduce((attrs, attr) => Object.assign(attrs, processAttribute(attr)), {});
}
function parseElement(element, typePrefix) {
const type = parseElementType(element, typePrefix);
const props = parseElementAttrs(element);
const jsonNode = {
type,
props: Object.keys(props).length > 0 ? props : null,
children: []
};
return jsonNode;
}
function parseLiteral(literal) {
const isNotJustWhitespace = /\S+/.test(literal.raw);
if (isNotJustWhitespace && typeof literal.value === 'string') {
return literal.value;
}
}
class StackCache {
constructor() {
this.cache = [];
this.ids = [];
this.id = 0;
}
push(item) {
this.cache[this.id] = item;
this.ids.push(this.id);
this.id += 1;
return item;
}
pop() {
return this.cache[this.ids.pop()];
}
}
function parseJSX(jsx, callbacks, opts) {
const ast = acorn.parse(jsx, { plugins: { jsx: true } });
const typePrefix = opts.typePrefix ? `${ opts.typePrefix }.` : '';
const ast = acorn.parse(jsx, { plugins: { jsx: true } });
let root = null;
const nodes = [];
const cache = new StackCache();
traverseAST(ast, {
onEnter: element => {
let type;
if (element.name.type === 'JSXIdentifier') {
const name = element.name.name;
type = /^[A-Z]/.test(name) ? `${ typePrefix }${ name }` : name;
} else {
type = `${ typePrefix }${ element.name.object.name }.${ element.name.property.name }`;
}
callbacks.onEnter(cache.push(parseElement(element, typePrefix)));
},
onLeave: element => {
callbacks.onLeave(cache.pop());
},
onLiteral: literal => {
const string = parseLiteral(literal);
if (string) callbacks.onLiteral(string);
}
});
}
const props = element.attributes.reduce((attrs, attr) => Object.assign(attrs, processAttribute(attr)), {});
const jsonNode = {
type,
props: Object.keys(props).length > 0 ? props : null,
children: []
};
function createParser(opts = {}) {
return (jsx, callbacks) => parseJSX(jsx, callbacks, opts);
}
const lastNode = nodes[nodes.length - 1];
/***/ },
/* 1 */
/***/ function(module, exports, __webpack_require__) {
if (lastNode) {
lastNode.children.push(jsonNode);
"use strict";
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = createParser;
var _jsxParser = __webpack_require__(0);
var _jsxParser2 = _interopRequireDefault(_jsxParser);
var _jsonParser = __webpack_require__(4);
var _jsonParser2 = _interopRequireDefault(_jsonParser);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function createParser(type, opts) {
switch (type) {
case '.jsx':
return (0, _jsxParser2.default)(opts);
case '.json':
return (0, _jsonParser2.default)(opts);
default:
throw new Error(`Unsupported type ${ type }`);
}
}
/***/ },
/* 2 */
/***/ function(module, exports, __webpack_require__) {
"use strict";
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = transform;
var _jsxParser = __webpack_require__(0);
var _jsxParser2 = _interopRequireDefault(_jsxParser);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function transform(content, parse) {
let root = null;
const nodes = [];
const getLastNode = () => nodes[nodes.length - 1];
const callbacks = {
onEnter: node => {
const lastNode = getLastNode();
if (typeof lastNode === 'object') {
lastNode.children.push(node);
} else {
root = jsonNode;
root = node;
}
nodes.push(jsonNode);
nodes.push(node);
},
onLeave: element => {
onLeave: node => {
nodes.pop();
},
onLiteral: literal => {
const lastNode = nodes[nodes.length - 1];
if (/\S+/.test(literal.raw)) {
lastNode.children.push(literal.value);
const lastNode = getLastNode();
if (typeof lastNode === 'object') {
lastNode.children.push(literal);
}
}
});
};
if (!root) throw new Error('Could not parse JSX.');else return root;
parse(content, callbacks);
if (!root || typeof root !== 'object') throw new Error('Could not parse JSX.');else return root;
}
/***/ },
/* 1 */
/* 3 */
/***/ function(module, exports, __webpack_require__) {

@@ -196,29 +307,115 @@

});
exports.parse = undefined;
let parse = exports.parse = (() => {
var _transform = __webpack_require__(2);
var _transform2 = _interopRequireDefault(_transform);
var _parsers = __webpack_require__(1);
var _parsers2 = _interopRequireDefault(_parsers);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
exports.default = (() => {
var _ref = _asyncToGenerator(function* (file, opts) {
switch (file.extname) {
case '.jsx':
return (0, _jsxParser2.default)(file.content, opts);
default:
throw new Error(`Unsupported file type ${ file.extname }`);
}
return (0, _transform2.default)(file.content, (0, _parsers2.default)(file.extname, opts));
});
return function parse(_x, _x2) {
function parse(_x, _x2) {
return _ref.apply(this, arguments);
};
}
return parse;
})();
var _jsxParser = __webpack_require__(0);
/***/ },
/* 4 */
/***/ function(module, exports) {
var _jsxParser2 = _interopRequireDefault(_jsxParser);
"use strict";
'use strict';
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = createParser;
const defaultJsonMap = {
typeKeys: ['type'],
childrenKeys: ['children'],
literalKeys: [],
ignoreKeys: []
};
function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
function findType(json, typeKeys) {
for (let key of typeKeys) {
if (key in json && typeof json[key] === 'string') {
return json[key];
}
}
}
function processJSONObject(json, callbacks, opts) {
const jsonMap = opts.jsonMap || defaultJsonMap;
const type = findType(json, jsonMap.typeKeys);
const props = {};
const childrenAndLiteralKeys = [];
for (let key of Object.keys(json)) {
if (jsonMap.childrenKeys.includes(key)) {
childrenAndLiteralKeys.push(key);
} else if (jsonMap.literalKeys.includes(key)) {
childrenAndLiteralKeys.push(key);
} else if (!jsonMap.ignoreKeys.includes(key) && !jsonMap.typeKeys.includes(key)) {
props[key] = json[key];
}
}
let jsonNode = null;
if (type) {
jsonNode = {
type,
props: Object.keys(props).length > 0 ? props : null,
children: []
};
}
if (jsonNode) callbacks.onEnter(jsonNode);
for (let key of childrenAndLiteralKeys) {
if (jsonMap.childrenKeys.includes(key) && jsonNode && json[key] && typeof json[key] === 'object') {
parseJSON(json[key], callbacks, opts);
} else if (jsonMap.literalKeys.includes(key) && typeof json[key] === 'string') {
callbacks.onLiteral(json[key]);
}
}
if (jsonNode) callbacks.onLeave(jsonNode);
}
function parseJSON(json, callbacks, opts) {
if (Array.isArray(json)) {
for (let object of json) {
if (object && typeof object === 'object') {
processJSONObject(object, callbacks, opts);
} else if (typeof object === 'string') {
callbacks.onLiteral(object);
}
}
} else {
processJSONObject(json, callbacks, opts);
}
}
function createParser(opts = {}) {
return (json, callbacks) => {
const object = typeof json === 'string' ? JSON.parse(json) : json;
return parseJSON(object, callbacks, opts);
};
}
/***/ },
/* 2 */
/* 5 */
/***/ function(module, exports) {

@@ -225,0 +422,0 @@

@@ -6,5 +6,6 @@ // @flow

import yargs from 'yargs'
import { parse } from './'
import parse from './'
import type { File, ParseOptions } from './'
import type { File } from './'
import type { ParseOptions } from './parsers'

@@ -11,0 +12,0 @@ type Options = {|

// @flow
import parseJSX from './parsers/jsx-parser'
import transform from './transform'
import createParser from './parsers'
import type { ParseOptions } from './parsers'
export type FileType = '.jsx' | '.json' | '.yaml' | '.xml';
export type File = {|
content: string;
extname: '.jsx' | '.json' | '.yaml' | '.xml';
extname: FileType;
|};
export type ParseOptions = {
typePrefix?: string;
};
export async function parse(file: File, opts: ParseOptions): Promise<Object> {
switch(file.extname) {
case '.jsx':
return parseJSX(file.content, opts)
default:
throw new Error(`Unsupported file type ${file.extname}`)
}
export default async function parse(file: File, opts: ParseOptions): Promise<*> {
return transform(file.content, createParser(file.extname, opts))
}

@@ -5,2 +5,4 @@ // @flow

import type { ParseOptions, ParseResult, ParseCallbacks } from './'
type AST = {

@@ -71,29 +73,8 @@ type: string;

type JsonNode = {
type: string;
props: Object | null;
children: Array<JsonNode>;
};
type JsonData = {
result: JsonNode | null;
nodes: Array<JsonNode>;
};
type ProcessingOptions = {|
type ProcessingCallbacks = {|
onEnter: (element: Element) => void;
onLeave: (element: Element) => void;
onLiteral: (literal: Object) => void;
onLiteral: (literal: Literal) => void;
|};
type ParseOptions = {
typePrefix?: string;
}
type ParseResult = {
type: string;
props: Object | null;
children: Array<ParseResult>;
}
function processAttribute(attribute: Attribute): {[key: string]: mixed} {

@@ -123,4 +104,2 @@ const value = attribute.value

}
default:
result = null
}

@@ -130,69 +109,103 @@ return {[attribute.name.name]: result}

function processExpression(expression: Expression, opts: ProcessingOptions) {
function processExpression(expression: Expression, callbacks: ProcessingCallbacks) {
if (expression.type === 'JSXElement') {
opts.onEnter(expression.openingElement)
callbacks.onEnter(expression.openingElement)
for (let child of expression.children) {
processExpression(child, opts, expression)
processExpression(child, callbacks)
}
opts.onLeave(expression.openingElement)
callbacks.onLeave(expression.openingElement)
}
if (expression.type === 'Literal') {
opts.onLiteral(expression)
callbacks.onLiteral(expression)
}
}
function traverseAST(ast: AST, opts: ProcessingOptions) {
function traverseAST(ast: AST, callbacks: ProcessingCallbacks) {
for (let statement of ast.body) {
const expression = statement.expression;
processExpression(expression, opts)
processExpression(expression, callbacks)
}
}
export default function parse(jsx: string, opts: ParseOptions): ParseResult {
const typePrefix = opts.typePrefix ? `${opts.typePrefix}.` : ''
const ast: AST = acorn.parse(jsx, {plugins: {jsx: true}})
let root = null
const nodes = []
function parseElementType(element: Element, typePrefix: string): string {
if (element.name.type === 'JSXIdentifier') {
const name = element.name.name
const isCustomClassName = /^[A-Z]/.test(name)
return isCustomClassName ? `${typePrefix}${name}` : name
}
else if (element.name.type === 'JSXMemberExpression') {
return `${typePrefix}${element.name.object.name}.${element.name.property.name}`
}
else {
throw new Error(`Unsupported element name type ${element.name.type}`)
}
}
traverseAST(ast, {
onEnter: (element: Element) => {
let type
if (element.name.type === 'JSXIdentifier') {
const name = element.name.name
type = /^[A-Z]/.test(name) ? `${typePrefix}${name}` : name
} else {
type = `${typePrefix}${element.name.object.name}.${element.name.property.name}`
}
function parseElementAttrs(element: Element): { [key: string]: mixed } {
return element.attributes.reduce((attrs, attr) => Object.assign(attrs, processAttribute(attr)), {})
}
const props = element.attributes.reduce((attrs, attr) => Object.assign(attrs, processAttribute(attr)), {})
const jsonNode = {
type,
props: Object.keys(props).length > 0 ? props : null,
children: []
}
function parseElement(element: Element, typePrefix: string): ParseResult {
const type = parseElementType(element, typePrefix)
const props = parseElementAttrs(element)
const jsonNode: ParseResult = {
type,
props: Object.keys(props).length > 0 ? props : null,
children: ([]: Array<ParseResult>)
}
return jsonNode
}
const lastNode = nodes[nodes.length - 1]
function parseLiteral(literal: Literal): ?string {
const isNotJustWhitespace = /\S+/.test(literal.raw)
if (isNotJustWhitespace && typeof literal.value === 'string') {
return literal.value
}
}
if (lastNode) {
lastNode.children.push(jsonNode)
} else {
root = jsonNode
}
class StackCache<T> {
cache: Array<T>;
ids: Array<number>;
id: number;
nodes.push(jsonNode)
constructor() {
this.cache = []
this.ids = []
this.id = 0
}
push(item: T): T {
this.cache[this.id] = item
this.ids.push(this.id)
this.id += 1
return item
}
pop(): T {
return this.cache[this.ids.pop()]
}
}
function parseJSX(jsx: string, callbacks: ParseCallbacks, opts: ParseOptions) {
const ast: AST = acorn.parse(jsx, {plugins: {jsx: true}})
const typePrefix = opts.typePrefix ? `${opts.typePrefix}.` : ''
const cache = new StackCache()
traverseAST(ast, {
onEnter: (element: Element) => {
callbacks.onEnter(cache.push(parseElement(element, typePrefix)))
},
onLeave: (element: Element) => {
nodes.pop()
callbacks.onLeave(cache.pop())
},
onLiteral: (literal: Object) => {
const lastNode = nodes[nodes.length - 1]
if (/\S+/.test(literal.raw)) {
lastNode.children.push(literal.value)
}
onLiteral: (literal: Literal) => {
const string = parseLiteral(literal)
if (string) callbacks.onLiteral(string)
}
})
}
if(!root) throw new Error('Could not parse JSX.')
else return root
export default function createParser(opts: ParseOptions = {}) {
return (jsx: string, callbacks: ParseCallbacks) => parseJSX(jsx, callbacks, opts)
}
{
"name": "tessellate-transform",
"version": "1.0.0",
"version": "1.1.0",
"description": "Tessellate JSX/JSON transformer.",

@@ -5,0 +5,0 @@ "author": "Maximilian Fellner <maximilian.fellner@zalando.de>",

@@ -8,2 +8,4 @@ # tessellate-transform

```javascript
import transform from 'tessellate-transform'
const file = {

@@ -14,3 +16,3 @@ content: '<h1>Hello, world!</h1>',

const options = {}
const object = await parse(file, options)
const object = await transform(file, options)
```

@@ -17,0 +19,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc