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

ink

Package Overview
Dependencies
Maintainers
2
Versions
76
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ink - npm Package Compare versions

Comparing version 2.0.0-6 to 2.0.0-7

build/dom.js

8

build/clone-element.js

@@ -8,2 +8,4 @@ "use strict";

var _dom = require("./dom");
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }

@@ -15,6 +17,6 @@

if (element.nodeValue) {
return document.createTextNode(element.nodeValue);
return (0, _dom.createTextNode)(element.nodeValue);
}
const newElement = document.createElement(element.nodeName);
const newElement = (0, _dom.createElement)(element.nodeName);
newElement.style = _objectSpread({}, element.style);

@@ -28,3 +30,3 @@ newElement.static = element.static;

for (const childNode of element.childNodes) {
newElement.appendChild(cloneElement(document, childNode));
(0, _dom.appendChild)(newElement, cloneElement(document, childNode));
}

@@ -31,0 +33,0 @@

@@ -77,3 +77,3 @@ "use strict";

// eslint-disable-line camelcase
children: _propTypes.default.node.isRequired
children: _propTypes.default.node
});

@@ -80,0 +80,0 @@

@@ -10,5 +10,7 @@ "use strict";

var _dom = require("./dom");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var _default = (document, onRender) => {
var _default = onRender => {
const rootHostContext = {};

@@ -26,3 +28,3 @@ const childHostContext = {};

createInstance: (type, newProps) => {
const element = document.createElement(type);
const node = (0, _dom.createNode)(type);

@@ -33,29 +35,29 @@ for (const [key, value] of Object.entries(newProps)) {

// Text node must be wrapped in another node, so that text can be aligned within container
const textElement = document.createElement('span');
const textElement = (0, _dom.createNode)('span');
textElement.textContent = value;
element.appendChild(textElement);
(0, _dom.appendChildNode)(node, textElement);
}
} else if (key === 'style') {
Object.assign(element.style, value);
Object.assign(node.style, value);
} else if (key === 'unstable__transformChildren') {
element.unstable__transformChildren = value; // eslint-disable-line camelcase
node.unstable__transformChildren = value; // eslint-disable-line camelcase
} else if (key === 'static') {
element.static = true;
node.static = true;
} else {
element.setAttribute(key, value);
(0, _dom.setAttribute)(node, key, value);
}
}
return element;
return node;
},
createTextInstance: text => document.createTextNode(text),
resetTextContent: element => {
if (element.textContent) {
element.textContent = '';
createTextInstance: _dom.createTextNode,
resetTextContent: node => {
if (node.textContent) {
node.textContent = '';
}
if (element.childNodes.length > 0) {
for (const childNode of element.childNodes) {
if (node.childNodes.length > 0) {
for (const childNode of node.childNodes) {
childNode.yogaNode.free();
element.removeChild(childNode);
(0, _dom.removeChildNode)(node, childNode);
}

@@ -65,30 +67,30 @@ }

getPublicInstance: instance => instance,
appendInitialChild: (parent, child) => parent.appendChild(child),
appendChild: (parent, child) => parent.appendChild(child),
insertBefore: (parent, child, beforeChild) => parent.insertBefore(child, beforeChild),
appendInitialChild: _dom.appendChildNode,
appendChild: _dom.appendChildNode,
insertBefore: _dom.insertBeforeNode,
finalizeInitialChildren: () => {},
supportsMutation: true,
appendChildToContainer: (parent, child) => {
parent.appendChild(child);
appendChildToContainer: (parentNode, childNode) => {
(0, _dom.appendChildNode)(parentNode, childNode);
onRender();
},
removeChildFromContainer: (parent, child) => {
parent.removeChild(child);
removeChildFromContainer: (parentNode, childNode) => {
(0, _dom.removeChildNode)(parentNode, childNode);
onRender();
},
prepareUpdate: () => true,
commitUpdate: (element, updatePayload, type, oldProps, newProps) => {
commitUpdate: (node, updatePayload, type, oldProps, newProps) => {
for (const [key, value] of Object.entries(newProps)) {
if (key === 'children') {
if (typeof value === 'string' || typeof value === 'number') {
element.childNodes[0].textContent = value;
node.childNodes[0].textContent = value;
}
} else if (key === 'style') {
Object.assign(element.style, value);
Object.assign(node.style, value);
} else if (key === 'unstable__transformChildren') {
element.unstable__transformChildren = value; // eslint-disable-line camelcase
node.unstable__transformChildren = value; // eslint-disable-line camelcase
} else if (key === 'static') {
element.static = true;
node.static = true;
} else {
element.setAttribute(key, value);
(0, _dom.setAttribute)(node, key, value);
}

@@ -99,8 +101,13 @@ }

},
commitTextUpdate: (element, oldText, newText) => {
element.textContent = newText;
commitTextUpdate: (node, oldText, newText) => {
if (node.nodeName === '#text') {
node.nodeValue = newText;
} else {
node.textContent = newText;
}
onRender();
},
removeChild: (parent, child) => {
parent.removeChild(child);
removeChild: (parentNode, childNode) => {
(0, _dom.removeChildNode)(parentNode, childNode);
onRender();

@@ -107,0 +114,0 @@ }

@@ -12,4 +12,2 @@ "use strict";

var _undom = _interopRequireDefault(require("undom"));
var _applyStyles = _interopRequireDefault(require("./apply-styles"));

@@ -19,21 +17,33 @@

var _cloneElement = _interopRequireDefault(require("./clone-element"));
var _dom = require("./dom");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const buildElement = (element, {
config,
terminalWidth,
skipStaticElements
}) => {
const node = _yogaLayoutPrebuilt.default.Node.create(config);
const measureText = text => {
const width = (0, _widestLine.default)(text);
const height = text.split('\n').length;
return {
width,
height
};
}; // Traverse the node tree, create Yoga nodes and assign styles to each Yoga node
const style = element.style || {};
element.yogaNode = node; // Root element of the tree
if (element.nodeName === 'BODY') {
node.setWidth(terminalWidth);
const buildLayout = (node, options) => {
const {
config,
terminalWidth,
skipStaticElements
} = options;
if (element.childNodes.length > 0) {
const childNodes = element.childNodes.filter(childNode => {
const yogaNode = _yogaLayoutPrebuilt.default.Node.create(config);
node.yogaNode = yogaNode;
const style = node.style || {}; // Root node of the tree
if (node.nodeName === 'ROOT') {
yogaNode.setWidth(terminalWidth);
if (node.childNodes.length > 0) {
const childNodes = node.childNodes.filter(childNode => {
return skipStaticElements ? !childNode.static : true;

@@ -43,49 +53,45 @@ });

for (const [index, childNode] of Object.entries(childNodes)) {
const {
yogaNode
} = buildElement(childNode, {
config,
terminalWidth,
skipStaticElements
});
node.insertChild(yogaNode, index);
const childYogaNode = buildLayout(childNode, options).yogaNode;
yogaNode.insertChild(childYogaNode, index);
}
}
return element;
} // Element which has text node as the only child
return node;
} // Apply margin, padding, flex, etc styles
if (element.textContent) {
const width = (0, _widestLine.default)(element.textContent);
const height = element.textContent.split('\n').length;
node.setWidth(style.width || width);
node.setHeight(style.height || height);
(0, _applyStyles.default)(node, style);
return element;
(0, _applyStyles.default)(yogaNode, style); // Nodes with only text have a child Yoga node dedicated for that text
if (node.textContent) {
const {
width,
height
} = measureText(node.textContent);
yogaNode.setWidth(style.width || width);
yogaNode.setHeight(style.height || height);
return node;
} // Text node
if (element.nodeValue) {
const width = (0, _widestLine.default)(element.nodeValue);
const height = element.nodeValue.split('\n').length;
node.setWidth(width);
node.setHeight(height);
(0, _applyStyles.default)(node, style);
return element;
} // All the other elements
if (node.nodeValue) {
const {
width,
height
} = measureText(node.nodeValue);
yogaNode.setWidth(width);
yogaNode.setHeight(height);
return node;
} // Nodes with other nodes as children
if (style.width) {
node.setWidth(style.width);
yogaNode.setWidth(style.width);
}
if (style.height) {
node.setHeight(style.height);
yogaNode.setHeight(style.height);
}
(0, _applyStyles.default)(node, style);
if (element.childNodes.length > 0) {
const childNodes = element.childNodes.filter(childNode => {
if (node.childNodes.length > 0) {
const childNodes = node.childNodes.filter(childNode => {
return skipStaticElements ? !childNode.static : true;

@@ -96,115 +102,115 @@ });

const {
yogaNode
} = buildElement(childNode, {
config,
terminalWidth,
skipStaticElements
});
node.insertChild(yogaNode, index);
yogaNode: childYogaNode
} = buildLayout(childNode, options);
yogaNode.insertChild(childYogaNode, index);
}
}
return element;
};
return node;
}; // After nodes are laid out, render each to output object, which later gets rendered to terminal
const renderElement = (element, output, offsetX = 0, offsetY = 0, {
const renderNodeToOutput = (node, output, offsetX = 0, offsetY = 0, {
transformers,
skipStaticElements
}) => {
if (element.static && skipStaticElements) {
if (node.static && skipStaticElements) {
return;
}
const node = element.yogaNode;
const x = offsetX + node.getComputedLeft();
const y = offsetY + node.getComputedTop();
const {
yogaNode
} = node; // Left and top positions in Yoga are relative to their parent node
const x = offsetX + yogaNode.getComputedLeft();
const y = offsetY + yogaNode.getComputedTop(); // Transformers are functions that transform final text output of each component
// See Output class for logic that applies transformers
let newTransformers = transformers;
if (element.unstable__transformChildren) {
newTransformers = [element.unstable__transformChildren, ...transformers];
} // Element with a text node
if (node.unstable__transformChildren) {
newTransformers = [node.unstable__transformChildren, ...transformers];
}
const newOptions = {
transformers: newTransformers,
skipStaticElements
}; // Text nodes
if (element.textContent && element.nodeName !== '#text') {
output.write(x, y, element.textContent, {
transformers: newTransformers,
skipStaticElements
});
return;
} // Text node
const text = node.textContent || node.nodeValue;
if (element.nodeName === '#text') {
output.write(x, y, element.nodeValue, {
transformers: newTransformers,
skipStaticElements
});
if (text) {
output.write(x, y, text, newOptions);
return;
} // All the other elements who have children
} // Nodes that have other nodes as children
for (const childElement of element.childNodes) {
renderElement(childElement, output, x, y, {
transformers: newTransformers,
skipStaticElements
});
for (const childNode of node.childNodes) {
renderNodeToOutput(childNode, output, x, y, newOptions);
}
};
}; // Since <Static> components can be placed anywhere in the tree, this helper finds and returns them
const getStaticElements = element => {
const staticElements = [];
const getStaticNodes = element => {
const staticNodes = [];
for (const childNode of element.childNodes) {
if (childNode.static) {
staticElements.push(childNode);
staticNodes.push(childNode);
}
if (childNode.childNodes.length > 0) {
staticElements.push(...getStaticElements(childNode));
if (Array.isArray(childNode.childNodes) && childNode.childNodes.length > 0) {
staticNodes.push(...getStaticNodes(childNode));
}
}
return staticElements;
};
return staticNodes;
}; // Build layout, apply styles, build text output of all nodes and return it
var _default = ({
terminalWidth
}) => {
const config = _yogaLayoutPrebuilt.default.Config.create(); // Used to free up memory used by last node tree
const config = _yogaLayoutPrebuilt.default.Config.create(); // Used to free up memory used by last Yoga node tree
let lastNode;
let lastStaticNode;
return element => {
if (lastNode) {
lastNode.freeRecursive();
let lastYogaNode;
let lastStaticYogaNode;
return node => {
if (lastYogaNode) {
lastYogaNode.freeRecursive();
}
if (lastStaticNode) {
lastStaticNode.freeRecursive();
if (lastStaticYogaNode) {
lastStaticYogaNode.freeRecursive();
}
const staticElements = getStaticElements(element);
const staticElements = getStaticNodes(node);
if (staticElements.length > 1) {
console.error('Warning: There can only be one <Static> component');
}
if (process.env.NODE_ENV !== 'production') {
console.error('Warning: There can only be one <Static> component');
}
} // <Static> component must be built and rendered separately, so that the layout of the other output is unaffected
let staticOutput;
if (staticElements.length === 1) {
const document = (0, _undom.default)();
document.body.appendChild((0, _cloneElement.default)(document, staticElements[0]));
const staticNode = buildElement(document.body, {
const rootNode = (0, _dom.createNode)('root');
(0, _dom.appendChildNode)(rootNode, staticElements[0]);
const {
yogaNode: staticYogaNode
} = buildLayout(rootNode, {
config,
terminalWidth,
skipStaticElements: false
}).yogaNode;
staticNode.calculateLayout(_yogaLayoutPrebuilt.default.UNDEFINED, _yogaLayoutPrebuilt.default.UNDEFINED, _yogaLayoutPrebuilt.default.DIRECTION_LTR); // Save current node tree to free up memory later
});
staticYogaNode.calculateLayout(_yogaLayoutPrebuilt.default.UNDEFINED, _yogaLayoutPrebuilt.default.UNDEFINED, _yogaLayoutPrebuilt.default.DIRECTION_LTR); // Save current Yoga node tree to free up memory later
lastStaticNode = staticNode;
lastStaticYogaNode = staticYogaNode;
staticOutput = new _output.default({
height: staticNode.getComputedHeight()
height: staticYogaNode.getComputedHeight()
});
renderElement(document.body, staticOutput, 0, 0, {
renderNodeToOutput(rootNode, staticOutput, 0, 0, {
transformers: [],

@@ -215,14 +221,16 @@ skipStaticElements: false

const node = buildElement(element, {
const {
yogaNode
} = buildLayout(node, {
config,
terminalWidth,
skipStaticElements: true
}).yogaNode;
node.calculateLayout(_yogaLayoutPrebuilt.default.UNDEFINED, _yogaLayoutPrebuilt.default.UNDEFINED, _yogaLayoutPrebuilt.default.DIRECTION_LTR); // Save current node tree to free up memory later
});
yogaNode.calculateLayout(_yogaLayoutPrebuilt.default.UNDEFINED, _yogaLayoutPrebuilt.default.UNDEFINED, _yogaLayoutPrebuilt.default.DIRECTION_LTR); // Save current node tree to free up memory later
lastNode = node;
lastYogaNode = yogaNode;
const output = new _output.default({
height: node.getComputedHeight()
height: yogaNode.getComputedHeight()
});
renderElement(element, output, 0, 0, {
renderNodeToOutput(node, output, 0, 0, {
transformers: [],

@@ -229,0 +237,0 @@ skipStaticElements: true

@@ -8,2 +8,10 @@ "use strict";

/**
* Naive string diff algorithm
*
* It's used to detect only new additions to the previous string and it expects previous string to never change.
* This function subtracts previous output from the new output and returns the difference.
*
* Used only for diffing output of <Static> component.
*/
var _default = (previous, next) => {

@@ -20,14 +28,15 @@ if (!previous) {

const nextLines = next.split('\n');
const lineCount = Math.max(previousLines.length, nextLines.length);
const diff = [];
for (let lineIndex = 0; lineIndex < lineCount; lineIndex++) {
if (previousLines[lineIndex] !== nextLines[lineIndex]) {
diff.push(nextLines[lineIndex]);
}
if (previousLines.length === nextLines.length) {
return next;
}
return diff.join('\n');
if (nextLines.length < previousLines.length) {
throw new TypeError('Output of <Static> component has become smaller. <Static> component requires existing children to stay the same in order to correctly detect new children and write them to output stream. Ensure that only new children get added to <Static> component and existing children produce the same output on every render.');
}
const diffStartIndex = nextLines.length - previousLines.length;
return nextLines.slice(diffStartIndex + 1).join('\n');
};
exports.default = _default;

@@ -14,2 +14,10 @@ "use strict";

/**
* "Virtual" output class
*
* Handles the positioning and saving of the output of each node in the tree.
* Also responsible for applying transformations to each character of the output.
*
* Used to generate the final output of all nodes before writing it to actual output stream (e.g. stdout)
*/
class Output {

@@ -19,2 +27,3 @@ constructor({

}) {
// Initialize output array with a specific set of rows, so that margin/padding at the bottom is preserved
this.output = new Array(height);

@@ -35,4 +44,9 @@ }

this.output[y + offsetY] = [];
}
} // Since number of characters displayed visually isn't equal to actual number of characters
// because of ANSI escapes, use `sliceAnsi` module to retrieve actual character along with
// ANSI escapes that wrap it and apply transformations to it
//
// It results in a lot more ANSI escapes in the output, but it produces correct output
let char = (0, _sliceAnsi.default)(line, offsetX, offsetX + 1);

@@ -53,6 +67,10 @@

let ret = '';
const rows = this.output.length;
for (let y = 0; y < this.output.length; y++) {
for (let y = 0; y < rows; y++) {
if (this.output[y]) {
for (let x = 0; x < this.output[y].length; x++) {
const columns = this.output[y].length;
for (let x = 0; x < columns; x++) {
// Treat empty columns as spaces
ret += this.output[y][x] || ' ';

@@ -59,0 +77,0 @@ }

@@ -10,4 +10,2 @@ "use strict";

var _undom = _interopRequireDefault(require("undom"));
var _logUpdate = _interopRequireDefault(require("log-update"));

@@ -23,2 +21,4 @@

var _dom = require("./dom");
var _App = _interopRequireDefault(require("./components/App"));

@@ -33,2 +33,3 @@

var _default = (node, options = {}) => {
// Stream was passed instead of `options` object
if (typeof options.write === 'function') {

@@ -46,3 +47,3 @@ options = {

}, options);
const document = (0, _undom.default)();
const rootNode = (0, _dom.createNode)('root');
const render = (0, _createRenderer.default)({

@@ -55,4 +56,5 @@ terminalWidth: options.stdout.columns

let ignoreRender = false; // Store last <Static> output to only rerender when needed
let ignoreRender = false; // Store last output to only rerender when needed
let lastOutput = '';
let lastStaticOutput = '';

@@ -68,3 +70,3 @@

staticOutput
} = render(document.body);
} = render(rootNode);

@@ -82,13 +84,17 @@ if (options.debug) {

options.stdout.write((0, _diffString.default)(lastStaticOutput, staticOutput));
log(output);
lastStaticOutput = staticOutput;
}
log(output);
if (output !== lastOutput) {
log(output);
lastOutput = output;
}
};
const debouncedRender = options.debug ? onRender : (0, _lodash.default)(onRender, 50, {
const throttledRender = options.debug ? onRender : (0, _lodash.default)(onRender, 50, {
leading: true,
trailing: true
});
const reconciler = options.stdout._inkReconciler || (0, _createReconciler.default)(document, debouncedRender);
const reconciler = options.stdout._inkReconciler || (0, _createReconciler.default)(throttledRender);

@@ -98,3 +104,3 @@ if (!options.stdout._ink) {

options.stdout._inkReconciler = reconciler;
options.stdout._inkContainer = reconciler.createContainer(document.body, false);
options.stdout._inkContainer = reconciler.createContainer(rootNode, false);
}

@@ -109,4 +115,4 @@

return () => {
if (typeof debouncedRender.cancel === 'function') {
debouncedRender.cancel();
if (typeof throttledRender.cancel === 'function') {
throttledRender.cancel();
onRender();

@@ -113,0 +119,0 @@ log.done();

{
"name": "ink",
"version": "2.0.0-6",
"version": "2.0.0-7",
"description": "React for CLI",

@@ -50,3 +50,2 @@ "license": "MIT",

"string-length": "^2.0.0",
"undom": "^0.4.0",
"widest-line": "^2.0.0",

@@ -53,0 +52,0 @@ "yoga-layout-prebuilt": "^1.9.3"

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