Skip to content

Commit

Permalink
Eslintify panel (#35)
Browse files Browse the repository at this point in the history
* Add lint script to package.json and .travis.yml

* Upgrade eslint-config-mixpanel to 3.5.0

* eslint --fix

* eslint-disable comments and manual fixes

* Add yarn.lock to .gitignore

* Ted's feedback

* explanation comment about no-unused-expressions
  • Loading branch information
nojvek authored Jun 13, 2018
1 parent 9ef7dd2 commit 0e15d37
Show file tree
Hide file tree
Showing 21 changed files with 224 additions and 220 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ build
test/fixtures/build.js
npm-debug.log
.DS_Store
yarn.lock
/.vscode
/isorender
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ node_js:
before_script:
- npm run build
- npm run build-test
- npm run lint
script:
- npm run test-server
- npm run test-browser-sauce
Expand Down
4 changes: 2 additions & 2 deletions lib/component-utils/proxy-component.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {h} from '../dom-patcher';
* @extends Component
*/
class ProxyComponent extends Component {
get config(){
get config() {
return Object.assign({
template: ({$component}) => {
return h($component.getTargetElementTag(), {
Expand Down Expand Up @@ -72,7 +72,7 @@ class ProxyComponent extends Component {
* }
* }
*/
allowEvent(ev) {
allowEvent(ev) { // eslint-disable-line no-unused-vars
return true;
}

Expand Down
51 changes: 25 additions & 26 deletions lib/component.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import cuid from 'cuid';
import pick from 'lodash.pick';
import WebComponent from 'webcomponent';

import { EMPTY_DIV, DOMPatcher, h } from './dom-patcher';
import {EMPTY_DIV, DOMPatcher, h} from './dom-patcher';
import Router from './router';

const DOCUMENT_FRAGMENT_NODE = 11;
Expand Down Expand Up @@ -108,7 +107,7 @@ class Component extends WebComponent {
*/
findPanelParentByTagName(tagName) {
tagName = tagName.toLowerCase();
for (let node = this.$panelParent; !!node; node = node.$panelParent) {
for (let node = this.$panelParent; node; node = node.$panelParent) {
if (node.tagName.toLowerCase() === tagName) {
return node;
}
Expand Down Expand Up @@ -166,7 +165,7 @@ class Component extends WebComponent {
* return state.largeResultSetID !== this._cachedResultID;
* }
*/
shouldUpdate(state) {
shouldUpdate(state) { // eslint-disable-line no-unused-vars
return true;
}

Expand Down Expand Up @@ -202,10 +201,10 @@ class Component extends WebComponent {

this.panelID = cuid();
this._config = Object.assign({}, {
css: '',
css: ``,
helpers: {},
routes: {},
template: () => { throw Error('No template provided by Component subclass'); },
template: () => { throw Error(`No template provided by Component subclass`); },
updateSync: false,
useShadowDom: false,
}, this.config);
Expand All @@ -222,13 +221,13 @@ class Component extends WebComponent {
this.isStateShared = false;
}

if (this.getConfig('useShadowDom')) {
this.el = this.attachShadow({mode: 'open'});
this.styleTag = document.createElement('style');
this.styleTag.innerHTML = this.getConfig('css');
if (this.getConfig(`useShadowDom`)) {
this.el = this.attachShadow({mode: `open`});
this.styleTag = document.createElement(`style`);
this.styleTag.innerHTML = this.getConfig(`css`);
this.el.appendChild(this.styleTag);
} else if (this.getConfig('css')) {
throw Error('"useShadowDom" config option must be set in order to use "css" config.');
} else if (this.getConfig(`css`)) {
throw Error(`"useShadowDom" config option must be set in order to use "css" config.`);
} else {
this.el = this;
}
Expand All @@ -248,11 +247,11 @@ class Component extends WebComponent {

this.$panelChildren = new Set();

if (typeof this.$panelParentID !== 'undefined') {
if (typeof this.$panelParentID !== `undefined`) {
this.isPanelChild = true;
// find $panelParent
for (let node = this.parentNode; node && !this.$panelParent; node = node.parentNode) {
if (node.nodeType === DOCUMENT_FRAGMENT_NODE) { // handle shadow-root
if (node.nodeType === DOCUMENT_FRAGMENT_NODE) { // handle shadow-root
node = node.host;
}
if (node.panelID === this.$panelParentID) {
Expand Down Expand Up @@ -280,20 +279,20 @@ class Component extends WebComponent {

const newState = Object.assign(
{},
this.getConfig('defaultState'),
this.getConfig(`defaultState`),
this.state,
this.getJSONAttribute('data-state'),
this.getJSONAttribute(`data-state`),
this._stateFromAttributes()
);
Object.assign(this.state, newState);

if (Object.keys(this.getConfig('routes')).length) {
if (Object.keys(this.getConfig(`routes`)).length) {
this.router = new Router(this, {historyMethod: this.historyMethod});
this.navigate(window.location.hash);
}

this.domPatcher = new DOMPatcher(this.state, this._render.bind(this), {
updateMode: this.getConfig('updateSync') ? 'sync': 'async',
updateMode: this.getConfig(`updateSync`) ? `sync`: `async`,
});
this.el.appendChild(this.domPatcher.el);
this.initialized = true;
Expand All @@ -320,7 +319,7 @@ class Component extends WebComponent {
}

attributeChangedCallback(attr, oldVal, newVal) {
if (attr === 'style-override') {
if (attr === `style-override`) {
this._applyStyles(newVal);
}
if (this.isPanelRoot && this.initialized) {
Expand All @@ -329,8 +328,8 @@ class Component extends WebComponent {
}

_applyStyles(styleOverride) {
if (this.getConfig('useShadowDom')) {
this.styleTag.innerHTML = this.getConfig('css') + (styleOverride || '');
if (this.getConfig(`useShadowDom`)) {
this.styleTag.innerHTML = this.getConfig(`css`) + (styleOverride || ``);
}
}

Expand All @@ -341,20 +340,20 @@ class Component extends WebComponent {
toString() {
try {
return `${this.tagName}#${this.panelID}`;
} catch(e) {
return 'UNKNOWN COMPONENT';
} catch (e) {
return `UNKNOWN COMPONENT`;
}
}

_render(state) {
if (this.shouldUpdate(state)) {
try {
this._rendered = this.getConfig('template')(Object.assign({}, state, {
this._rendered = this.getConfig(`template`)(Object.assign({}, state, {
$app: this.appState,
$component: this,
$helpers: this.helpers,
}));
} catch(e) {
} catch (e) {
this.logError(`Error while rendering ${this.toString()}`, this, e.stack);
}
}
Expand Down Expand Up @@ -411,7 +410,7 @@ class Component extends WebComponent {
} else {

// update DOM, router, descendants etc.
const updateHash = '$fragment' in stateUpdate && stateUpdate.$fragment !== this[store].$fragment;
const updateHash = `$fragment` in stateUpdate && stateUpdate.$fragment !== this[store].$fragment;
const cascadeFromRoot = cascade && !this.isPanelRoot;
const updateOptions = {cascade, store};
const rootOptions = {exclude: this, cascade, store};
Expand Down
26 changes: 13 additions & 13 deletions lib/dom-patcher.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@
import snabbdom from 'snabbdom';
import h from 'snabbdom/h';

import snabbAttributes from 'snabbdom/modules/attributes';
import snabbDataset from 'snabbdom/modules/dataset';
import snabbDelayedClass from 'snabbdom-delayed-class';
import snabbAttributes from 'snabbdom/modules/attributes';
import snabbDataset from 'snabbdom/modules/dataset';
import snabbDelayedClass from 'snabbdom-delayed-class';
import snabbEventlisterners from 'snabbdom/modules/eventlisteners';
import snabbProps from 'snabbdom/modules/props';
import snabbStyle from 'snabbdom/modules/style';
import snabbProps from 'snabbdom/modules/props';
import snabbStyle from 'snabbdom/modules/style';

const patch = snabbdom.init([
snabbAttributes,
Expand All @@ -23,24 +23,24 @@ const patch = snabbdom.init([
snabbStyle,
]);

export const EMPTY_DIV = h('div');
export const EMPTY_DIV = h(`div`);
export {h};

export class DOMPatcher {
constructor(initialState, renderFunc, options={}) {
this.updateMode = options.updateMode || 'async';
this.updateMode = options.updateMode || `async`;

this.state = Object.assign({}, initialState);
this.renderFunc = renderFunc;
this.vnode = this.renderFunc(this.state);

// prepare root element
const tagName = this.vnode.sel.split(/[#\.]/)[0];
const classMatches = this.vnode.sel.match(/\.[^\.#]+/g);
const idMatch = this.vnode.sel.match(/#[^\.#]+/);
const tagName = this.vnode.sel.split(/[#.]/)[0];
const classMatches = this.vnode.sel.match(/\.[^.#]+/g);
const idMatch = this.vnode.sel.match(/#[^.#]+/);
this.el = document.createElement(tagName);
if (classMatches) {
this.el.className = classMatches.map(c => c.slice(1)).join(' ');
this.el.className = classMatches.map(c => c.slice(1)).join(` `);
}
if (idMatch) {
this.el.id = idMatch[0].slice(1);
Expand All @@ -56,13 +56,13 @@ export class DOMPatcher {

this.pendingState = newState;
switch (this.updateMode) {
case 'async':
case `async`:
if (!this.pending) {
this.pending = true;
requestAnimationFrame(() => this.render());
}
break;
case 'sync':
case `sync`:
this.render();
break;
}
Expand Down
7 changes: 4 additions & 3 deletions lib/isorender/dom-shims.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-env node */
/**
* Node.js polyfill for rendering Panel components without a browser.
* Makes the following objects globally available:
Expand Down Expand Up @@ -27,7 +28,7 @@ import requestAnimationFrame from 'raf';
global.requestAnimationFrame = global.requestAnimationFrame || requestAnimationFrame;

// patch DOM insertion functions to call connectedCallback on Custom Elements
['appendChild', 'insertBefore', 'replaceChild'].forEach(funcName => {
[`appendChild`, `insertBefore`, `replaceChild`].forEach(funcName => {
const origFunc = Element.prototype[funcName];
Element.prototype[funcName] = function() {
const child = origFunc.apply(this, arguments);
Expand Down Expand Up @@ -76,7 +77,7 @@ Document.prototype.createElement = function(tagName) {
el = originalCreateElement(...arguments);
}
return el;
}
};

global.customElements = global.customElements || {
define(tagName, proto) {
Expand All @@ -86,5 +87,5 @@ global.customElements = global.customElements || {
} else {
registeredElements[tagName] = proto;
}
}
},
};
32 changes: 16 additions & 16 deletions lib/router.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,35 @@
function stripHash(fragment) {
return fragment.replace(/^#*/, ``);
}

// just the necessary bits of Backbone router+history
export default class Router {
constructor(app, options={}) {
// allow injecting window dep
const routerWindow = this.window = options.window || window;

this.app = app;
const routeDefs = this.app.getConfig('routes');
const routeDefs = this.app.getConfig(`routes`);

// https://github.com/jashkenas/backbone/blob/d682061a/backbone.js#L1476-L1479
// Cached regular expressions for matching named param parts and splatted
// parts of route strings.
const optionalParam = /\((.*?)\)/g;
const namedParam = /(\(\?)?:\w+/g;
const splatParam = /\*\w+/g;
const escapeRegExp = /[\-{}\[\]+?.,\\\^$|#\s]/g;
const namedParam = /(\(\?)?:\w+/g;
const splatParam = /\*\w+/g;
const escapeRegExp = /[\-{}\[\]+?.,\\\^$|#\s]/g; // eslint-disable-line no-useless-escape
this.compiledRoutes = Object.keys(routeDefs).map(routeExpr => {
// https://github.com/jashkenas/backbone/blob/d682061a/backbone.js#L1537-L1547
let expr = routeExpr
.replace(escapeRegExp, '\\$&')
.replace(optionalParam, '(?:$1)?')
.replace(namedParam, (match, optional) => optional ? match : '([^/?]+)')
.replace(splatParam, '([^?]*?)');
expr = new RegExp('^' + expr + '(?:\\?([\\s\\S]*))?$');
.replace(escapeRegExp, `\\$&`)
.replace(optionalParam, `(?:$1)?`)
.replace(namedParam, (match, optional) => optional ? match : `([^/?]+)`)
.replace(splatParam, `([^?]*?)`);
expr = new RegExp(`^` + expr + `(?:\\?([\\s\\S]*))?$`);

// hook up route handler function
let handler = routeDefs[routeExpr];
if (typeof handler === 'string') {
if (typeof handler === `string`) {
// reference to another handler rather than its own function
handler = routeDefs[handler];
}
Expand All @@ -34,9 +38,9 @@ export default class Router {
});

const navigateToHash = () => this.navigate(routerWindow.location.hash);
routerWindow.addEventListener('popstate', () => navigateToHash());
routerWindow.addEventListener(`popstate`, () => navigateToHash());

this.historyMethod = options.historyMethod || 'pushState';
this.historyMethod = options.historyMethod || `pushState`;
const origChangeState = routerWindow.history[this.historyMethod];
routerWindow.history[this.historyMethod] = function() {
origChangeState.apply(routerWindow.history, arguments);
Expand Down Expand Up @@ -89,7 +93,3 @@ export default class Router {
}
}
}

function stripHash(fragment) {
return fragment.replace(/^#*/, '');
}
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"build": "babel lib -d build && cp -r build/isorender .",
"build-test": "webpack --config test/browser/webpack.config.js",
"docs": "rm -rf docs && jsdoc lib lib/component-utils lib/isorender -t node_modules/minami -R README-API.md -d docs",
"lint": "eslint devtools hot lib scripts test --ignore-pattern 'test/browser/build/'",
"prepublishOnly": "npm run build",
"publish-devtools": "node scripts/publish-devtools.js",
"test": "npm run build-test && npm run test-server && npm run test-browser-local",
Expand Down Expand Up @@ -58,8 +59,8 @@
"babel-preset-es2015": "^6.6.0",
"chai": "^3.5.0",
"chrome-store-api": "^1.0.5",
"eslint": "4.12.1",
"eslint-config-mixpanel": "3.1.0",
"eslint": "4.18.1",
"eslint-config-mixpanel": "3.5.0",
"jsdoc": "^3.5.5",
"minami": "^1.1.1",
"mocha": "^2.5.3",
Expand Down
2 changes: 1 addition & 1 deletion scripts/publish-devtools.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const manifestPath = `${devtoolsDir}/manifest.json`;

// Main wrapped in async since top-level await is not supported
(async function() {
try{
try {
// Write new version to manifest
const manifest = JSON.parse(fs.readFileSync(manifestPath, `utf-8`));
console.log(`Current manifest:\n`, manifest);
Expand Down
2 changes: 1 addition & 1 deletion test/browser/component-utils/proxy-component.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ describe(`ProxyComponent`, function() {
});

it(`re-dispatches events from child that are not composed`, function(done) {
el.addEventListener(`nonComposedEvent`, () => done())
el.addEventListener(`nonComposedEvent`, () => done());
el.setAttribute(`send-non-composed`, ``);
});

Expand Down
6 changes: 3 additions & 3 deletions test/fixtures/attr-reflection-app.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Component, h } from '../../lib';
import {Component, h} from '../../lib';

export class AttrReflectionApp extends Component {
get config() {
return {
template: state => h('div', {class: {'attr-app': true}}, [
h('p', `Value of attribute wombats: ${this.getAttribute('wombats')}`),
template: () => h(`div`, {class: {'attr-app': true}}, [
h(`p`, `Value of attribute wombats: ${this.getAttribute(`wombats`)}`),
]),
};
}
Expand Down
Loading

0 comments on commit 0e15d37

Please sign in to comment.