November 7th, 2018 James DiGioia
const arr = [1, 2, 3];
const newArr = Array.from({ ...arr, 1: 3, length: arr.length });
console.log(newArr); // [1, 3, 3]
const arr = [1, 2, 3];
const newObj = { ...arr };
console.log(newObj); // {0: 1, 1: 2, 2: 3}
const arr = [1, 2, 3];
const newObj = { ...arr, 1: 3 };
console.log(newObj); // {0: 1, 1: 3, 2: 3}
November 4th, 2018 James DiGioia
diff --git a/deploy-hooks/build-before.yml b/deploy-hooks/build-before.yml
--- a/deploy-hooks/build-before.yml
+++ b/deploy-hooks/build-before.yml
+- name: Install npm dependencies
+ command: npm ci
+ connection: local
+ args:
+ chdir: "~/path/to/gatsby"
+
+- name: Compile assets for production
+ command: npm run build
+ connection: local
+ args:
+ chdir: "~/path/to/gatsby"
+
+- name: Copy production assets
+ synchronize:
+ src: "~/path/to/gatsby/public"
+ dest: "{{ deploy_helper.new_release_path }}"
+ group: no
+ owner: no
+ rsync_opts: --chmod=Du=rwx,--chmod=Dg=rx,--chmod=Do=rx,--chmod=Fu=rw,--chmod=Fg=r,--chmod=Fo=r
diff --git a/group_vars/development/wordpress_sites.yml b/group_vars/development/wordpress_sites.yml
--- a/group_vars/development/wordpress_sites.yml
+++ b/group_vars/development/wordpress_sites.yml
@@ -8,6 +8,7 @@ wordpress_sites:
- canonical: domain.test
local_path: ../site # path targeting local Bedrock site directory (relative to Ansible root)
admin_email: [email protected]
+ nginx_wordpress_site_conf: templates/domain.com.conf.j2
multisite:
enabled: false
ssl:
diff --git a/group_vars/production/wordpress_sites.yml b/group_vars/production/wordpress_sites.yml
index 48b69b9..99d775f 100644
--- a/group_vars/production/wordpress_sites.yml
+++ b/group_vars/production/wordpress_sites.yml
@@ -9,6 +9,7 @@ wordpress_sites:
local_path: ../site # path targeting local Bedrock site directory (relative to Ansible root)
repo: [email protected] :repo/domain.git # replace with your Git repo URL
branch: master
+ nginx_wordpress_site_conf: templates/domain.com.conf.j2
multisite:
enabled: false
ssl:
diff --git a/templates/domain.com.conf.j2 b/templates/domain.com.conf.j2
+++ b/templates/domain.com.conf.j2
+{% extends 'roles/wordpress-setup/templates/domain.com.conf.j2' %}
+
+{% block location_primary -%}
+location /wp-json {
+ try_files $uri $uri/ /index.php?$args;
+ }
+ location /wp/ {
+ try_files $uri $uri/ /wp/wp-admin/;
+ }
+ location / {
+ root {{ www_root }}/{{ item.key }}/{{ item.value.current_path | default('current') }}/public;
+ error_page 404 /404.html;
+ }
+{% endblock %}
June 28th, 2018 James DiGioia
const { findGitRepos, getCommitsFromRepos } = require ('./gitutils');
findGitRepos(['~/Code/Valtech'], 5, (err, result) => {
if (err) throw err;
getCommitsFromRepos(result, 30, (err, result) => {
if (err) throw err;
console.log(result);
});
});
// Stolen from here:
// https://github.com/notwaldorf/tiny-care-terminal/blob/78e038069f01c36148d7d486d7775275d3df1df8/gitbot.js
const resolve = require('resolve-dir');
const subdirs = require('subdirs');
const isGit = require('is-git');
const gitlog = require('gitlog');
const path = require('path');
const async = require("async");
const git = require('git-utils');
try {
const gitUsername = require('git-user-name')();
} catch(err) {
console.error(`ERROR reading git-config.
Use e.g. 'git config --global user.name "Mona Lisa"'.
See 'man git config' for further information.
`);
return process.exit(0);
}
/**
* Go through all `repos` and look for subdirectories up to a given `depth`
* and look for repositories.
* Calls `callback` with array of repositories.
*/
function findGitRepos(repos, depth, callback) {
let allRepos = [];
async.each(repos, (repo, repoDone) => {
repo = resolve(repo);
subdirs(repo, depth, (err, dirs) => {
if (err) {
switch (err.code) {
case 'ENOENT':
return callback(`Could not open directory directory: ${err.path}n`, null);
case 'EACCES':
return; //ignore if no access
default:
return callback(`Error "${err.code}" doing "${err.syscall}" on directory: ${err.path}n`, null);
}
}
if (dirs) dirs.push(repo);
async.each(dirs, (dir, dirDone) => {
isGit(dir, (err, isGit) => {
if (err) {
return callback(err, null);
}
if (!dir.includes('.git') && isGit) {
allRepos.push(dir);
}
dirDone();
});
}, repoDone);
});
}, err => {
callback(err, allRepos.sort().reverse());
});
}
/**
* returns all commits of the last given `days`.
* Calls `callback` with line-seperated-strings of the formatted commits.
*/
function getCommitsFromRepos(repos, days, callback) {
let cmts = [];
async.each(repos, (repo, repoDone) => {
let localGitUsername = '';
try {
const gitUtilsRepo = git.open(repo);
localGitUsername = gitUtilsRepo.getConfigValue('user.name') || gitUsername;
} catch (err) {
localGitUsername = gitUsername;
}
try {
gitlog({
repo: repo,
all: true,
number: 100, //max commit count
since: `${days} days ago`,
fields: ['abbrevHash', 'subject', 'authorDate', 'authorName'],
author: localGitUsername
}, (err, logs) => {
// Error
if (err) {
callback(`Oh noes😱nThe repo ${repo} has failed:n${err}`, null);
}
// Find user commits
let commits = [];
logs.forEach(c => {
// filter simple merge commits
if (c.status && c.status.length)
commits.push(`${c.abbrevHash} - ${c.subject} (${c.authorDate}) <${c.authorName.replace('@[email protected] ','')}>`);
});
// Add repo name and commits
if (commits.length >= 1) {
// Repo name
cmts.push(repo);
cmts.push(...commits);
}
repoDone();
});
} catch(err) {
callback(err, null);
}
}, err => {
callback(err, cmts.length > 0 ? cmts.join('n') : "Nothing yet. Start small!");
});
}
module.exports.findGitRepos = findGitRepos;
module.exports.getCommitsFromRepos = getCommitsFromRepos;
June 13th, 2018 James DiGioia
const elementToCursorMoveAction = R.converge(
R.unapply(editorCursorMoveAction),
[selectSelectionStart, selectSelectionEnd]
);
const elementToCursorMoveAction = e =>
editorCursorMoveAction([selectSelectionStart(e), selectSelectionEnd(e)]);
May 31st, 2018 James DiGioia
setTimeout(() => {
console.log('inside timeout');
}, 0);
process.nextTick(() => {
console.log('inside nextTick');
});
const p = new Promise(function(resolve, reject) {
console.log('inside promise');
resolve();
})
.then(() => console.log('inside then'));
console.log('after promise');
May 11th, 2018 James DiGioia
import t from 'elm-types';
const AddTodo = t.Constructor('AddTodo', [t.String]);
const RemoveTodo = t.Constructor('AddTodo', [t.String]);
const Action = t.Union('Action', [AddTodo]);
const Todo = t.Record('Todo', {
name: t.String,
completed: t.Bool
});
const Model = t.Record('Model', {
todos: t.List('todos', Todo)
});
// Throws if function is not passed correct parameter types
const update = t.Function('update', [Model, Action, Model], (state, action) =>
// Throws if last object is not exaustive
t.case(action, Action, {
[AddTodo]: add => ({
...state,
todos: [...state.todos, Todo(add, false)]
}),
[RemoveTodo]: remove => ({
...state,
todos: state.todos.filter(todo => todo.name === remove)
})
});
);
const store = createStore(update, Model([]));
const App = ({ todos }) => (
<div>
<h1>Todo List</h1>
<ul>
{todos.map(todo => (
<li onClick={() => store.dispatch(RemoveTodo(todo.name))}>
{todo.name}
</li>
))}
</ul>
</div>
);
const AppProps = t.Record('AppProps', {
todos: t.List('todos', Todo)
});
App.propTypes = t.PropTypes(AppProps);
render(
<App {...store.getState()} />,
document.getElementById('app')
);
April 15th, 2018 James DiGioia
function flatten(source, acc = []) {
if (source.length === 0) return acc;
const [head, ...tail] = source;
return flatten(tail, [...acc, ...(Array.isArray(head) ? flatten(head) : [head])]);
}
console.log(flatten([1,2,[3,4,5,[6,7],8,[9]],10]));
import * as R from 'ramda';
const flatten = R.ifElse(
R.propSatisfies(R.equals(0), 'length'),
R.flip(R.identity),
R.converge((source, acc = []) => flatten(source, acc), [
R.tail,
R.useWith(R.flip(R.concat), [
R.pipe(R.head, R.ifElse(Array.isArray, head => flatten(head, []), R.of)),
R.identity
])
])
);
console.log(flatten([1,2,[3,4,5,[6,7],8,[9]],10], []));
January 30th, 2018 James DiGioia
function foo(ddb) {
return {
listTables: (params = {}, cb = idFunc) => {
const self = this
let currentList = params.currentList || []
return toPromise(ddb, ddb.listTables, omit(params, 'currentList'), cb)
.then(r => {
console.log('LISTTABLES result', r)
currentList = currentList.concat(r.TableNames || [])
if (!r.LastEvaluatedTableName || r.TableNames.length === 0) {
return { ...r, TableNames: currentList }
}
return self.listTables({ // <- Fails here
...params,
currentList,
ExclusiveStartTableName: r.LastEvaluatedTableName,
}, cb)
})
}
}
}
class MyClass {
myMethod = () => {
// ...code
}
}
December 20th, 2017 James DiGioia
import { h, component } from 'brookjs'
import { editClick } from '../actions'
// Changes only occur when bound to a stream
export default component({
render: props$ => (
<li>
{/* Text changes when a value is emitted. */}
<p class="todo__name">
{props$.map(props => props.text)}
</p>
{/* Maps a stream of events to actions. */}
<button onClick={event$ => event$.map(editClick)}>
{'Edit todo'}
</button>
</li>
)
})
import { h, component } from 'brookjs'
import TodoItem from './TodoItem'
export default component({
render: props$ => (
<div>
<h2>My Todos</h2>
{/**
* `order` provides sequence todos should appear
* `dict` provides a performant instance lookup
*/}
<ul>
{props$.map(todos => todos.order.map(key => (
<TodoItem
props$={props$.map(todos => todos.dict[key])}
key={key}
preplug={instance$ => instance$.map(action => ({
...action,
meta: { key }
})} />
)))}
<ul>
</div>
)
})
import { h, component } from 'brookjs'
import TodoList from './TodoList'
export default component({
render: props$ => (
<div>
<h1>Todo App</h1>
{/**
* Individual attributes respond to observables
* Performance optimized inline
*/}
<input value={props$.map(props => props.editing).skipDuplicates()}
onInput={event$ => event$.map(event => editTodo(event.target.value))} />
<button onClick={event$ => event$.map(addTodo)}>Add Todo</button>
<TodoList props$={props$.map(props => props.todos)} />
</div>
)
})
import { createStore, applyMiddleware } from 'redux'
import { h, observeDelta, Kefir } from brookjs
import { App } from './components'
import { selectProps } from './selectors'
const store = createStore(
(state, action) => state, // reducer
window.__INITIAL_STATE__ || {},
applyMiddleware(observeDelta(
/* register deltas here */
)
)
const state$ = Kefir.fromESObservable(store)
/**
* `mount` thus takes the DOM to mount
* and the element to bind it to, and
* returns a stream. Note that because
* of how streams work, nothing happens
* until the stream is observed.
*/
const view$ = mount(
<App props$={selectProps(state$)} />,
document.getElementById('app')
)
view$.observe(store.dispatch)
import { h, component, list } from 'brookjs'
import TodoItem from './TodoItem'
export default component({
render: props$ => (
<div>
<h2>My Todos</h2>
<ul>
{/* Must be a stream of objects with `order` & `dict` */}
{list(props$, (props$, key) => (
<TodoItem
props$={props$}
key={key}
preplug={instance$ => instance$.map(action => ({
...action,
meta: { key }
})} />
)}
<ul>
</div>
)
})
import { createStore, applyMiddleware } from 'redux'
import { h, observeDelta, Kefir } from brookjs
import { App } from './components'
import { selectProps } from './selectors'
const el = document.getElementById('app')
const store = createStore(
(state, action) => state,
window.__INITIAL_STATE__ || {},
applyMiddleware(observeDelta(
/* register deltas here */
domDelta({ el, selectProps, view: App })
)
)
// Everything is bound to the store immediately,
// but an init action makes sure everything waits
// until the store is fully instantiated.
store.dispatch(init())
December 4th, 2017 James DiGioia
const pipe = (...funcs) => (...args) =>
funcs.reduce((args, func) => [func(...args)], args)[0];
// just reverse the funcs array...?
const compose = (...funcs) => (...args) =>
funcs.reverse().reduce((args, func) => [func(...args)], args)[0];