Commit 49c6e5459b68f2a30bcecf7727b8c9a99cfe4e79
progress
Michael Williams committed on 2/7/2017, 4:21:58 AMParent: ef43b604431498140a4cd01d0ff8e7961392bea0
Files changed
package.json | changed |
.babelrc | deleted |
.nvmrc | deleted |
bin/start | added |
bin/test | added |
.python-version | deleted |
browser.js | added |
.travis.yml | deleted |
browserEntry.js | added |
example/app/layout.js | added |
example/app/modules/layout.js | added |
example/app/pages/home.js | added |
example/cats/pages/one.js | added |
lib/app.js | added |
lib/mapModules.js | added |
lib/module.js | added |
lib/pathModule.js | added |
lib/readModules.js | added |
lib/readModules.test.js | added |
lib/scopeModule.js | added |
lib/transformModule.js | added |
modules/assets.js | added |
modules/http.js | added |
modules/index.js | added |
modules/log.js | added |
modules/router.js | added |
modules/store.js | added |
server.js | added |
tmp.js | added |
types/Module.js | added |
types/Page.js | added |
types/State.js | added |
types/index.js | added |
package.json | ||
---|---|---|
@@ -1,22 +1,50 @@ | ||
1 | 1 | { |
2 | 2 | "name": "catstack", |
3 | 3 | "version": "0.0.0", |
4 | 4 | "description": "modular framework for real-time data-driven apps", |
5 | - "scripts": {}, | |
5 | + "scripts": { | |
6 | + "example:start": "NODE_ENV=development cd example && node-dev ../bin/start" | |
7 | + }, | |
8 | + "browser": { | |
9 | + "./modules/assets.js": false | |
10 | + }, | |
6 | 11 | "repository": { |
7 | 12 | "type": "git", |
8 | - "url": "git+https://github.com/enspiral-craftworks/catstack.git" | |
13 | + "url": "git+https://github.com/enspiral-root-systems/catstack.git" | |
9 | 14 | }, |
10 | 15 | "keywords": [], |
11 | 16 | "author": "Mikey <michael.williams@enspiral.com> (http://dinosaur.is)", |
12 | 17 | "license": "ISC", |
13 | 18 | "bugs": { |
14 | - "url": "https://github.com/enspiral-craftworks/catstack/issues" | |
19 | + "url": "https://github.com/enspiral-root-systems/catstack/issues" | |
15 | 20 | }, |
16 | - "homepage": "https://github.com/enspiral-craftworks/catstack#readme", | |
21 | + "homepage": "https://github.com/enspiral-root-systems/catstack#readme", | |
17 | 22 | "engines": { |
18 | 23 | "node": "^6.0.0" |
19 | 24 | }, |
20 | - "devDependencies": {}, | |
21 | - "dependencies": {} | |
25 | + "devDependencies": { | |
26 | + "node-dev": "^3.1.3", | |
27 | + "tape": "^4.6.3" | |
28 | + }, | |
29 | + "dependencies": { | |
30 | + "browserify": "^14.0.0", | |
31 | + "bulk-require": "^1.0.0", | |
32 | + "bulkify": "github:ahdinosaur/bulkify", | |
33 | + "catstack-log": "github:catstack/catstack-log", | |
34 | + "depject": "^3.1.5", | |
35 | + "es2040": "^1.2.4", | |
36 | + "evalify": "^2.0.0", | |
37 | + "inu": "github:ahdinosaur/inu#v4", | |
38 | + "inu-engine": "github:ahdinosaur/inu-engine", | |
39 | + "inu-log": "github:ahdinosaur/inu-log#v2", | |
40 | + "inu-router": "github:ahdinosaur/inu-router", | |
41 | + "minimatch": "^3.0.3", | |
42 | + "modify-values": "^1.0.0", | |
43 | + "read-directory": "^2.0.0", | |
44 | + "require-from-string": "^1.2.1", | |
45 | + "value-pipe": "github:ahdinosaur/value-pipe", | |
46 | + "vas": "github:ahdinosaur/vas#v3", | |
47 | + "vas-assets": "github:ahdinosaur/vas-assets", | |
48 | + "vas-http": "github:ahdinosaur/vas-http" | |
49 | + } | |
22 | 50 | } |
.babelrc | ||
---|---|---|
@@ -1,28 +1,0 @@ | ||
1 | -{ | |
2 | - "presets": [ | |
3 | - "es2015", | |
4 | - "react" | |
5 | - ], | |
6 | - "plugins": [ | |
7 | - "transform-runtime", | |
8 | - "transform-object-rest-spread", | |
9 | - "transform-class-properties", | |
10 | - "lodash" | |
11 | - ], | |
12 | - "env": { | |
13 | - "hot": { | |
14 | - "plugins": [ | |
15 | - ["react-transform", { | |
16 | - "transforms": [{ | |
17 | - "transform": "react-transform-hmr", | |
18 | - "imports": ["react"], | |
19 | - "locals": ["module"] | |
20 | - }, { | |
21 | - "transform": "react-transform-catch-errors", | |
22 | - "imports": ["react", "redbox-react"] | |
23 | - }] | |
24 | - }] | |
25 | - ] | |
26 | - } | |
27 | - } | |
28 | -} |
.nvmrc | ||
---|---|---|
@@ -1,1 +1,0 @@ | ||
1 | -4 |
bin/start | ||
---|---|---|
@@ -1,0 +1,7 @@ | ||
1 | +#!/usr/bin/env node | |
2 | + | |
3 | +const server = require('../server') | |
4 | + | |
5 | +console.log('start') | |
6 | + | |
7 | +server() |
bin/test | ||
---|---|---|
@@ -1,0 +1,10 @@ | ||
1 | +#!/bin/sh | |
2 | + | |
3 | +if [ "$#" -gt 0 ] | |
4 | +then | |
5 | + getPaths="echo $@" | |
6 | +else | |
7 | + getPaths="find . -iname '*.test.js' -not -path './node_modules/*'" | |
8 | +fi | |
9 | + | |
10 | +eval "$getPaths" | xargs tape |
.python-version | ||
---|---|---|
@@ -1,1 +1,0 @@ | ||
1 | -2.7.10 |
browser.js | ||
---|---|---|
@@ -1,0 +1,17 @@ | ||
1 | +const pull = require('pull-stream') | |
2 | +const { entry } = require('inu') | |
3 | +const { update } = require('yo-yo') | |
4 | +const start = require('inu-engine') | |
5 | + | |
6 | +const app = require('./lib/app') | |
7 | + | |
8 | +module.exports = startBrowser | |
9 | + | |
10 | +function startBrowser () { | |
11 | + const sockets = app() | |
12 | + const store = entry(sockets) | |
13 | + const { views } = start(store) | |
14 | + const main = document.createElement('div') | |
15 | + document.body.appendChild(main) | |
16 | + pull(views(), pull.drain(update.bind(null, main))) | |
17 | +} |
.travis.yml | ||
---|---|---|
@@ -1,14 +1,0 @@ | ||
1 | -language: node_js | |
2 | -node_js: | |
3 | - - "4" | |
4 | - - "5" | |
5 | -env: | |
6 | - - CXX=g++-4.8 | |
7 | -addons: | |
8 | - apt: | |
9 | - sources: | |
10 | - - ubuntu-toolchain-r-test | |
11 | - packages: | |
12 | - - g++-4.8 | |
13 | -notifications: | |
14 | - email: false |
example/app/modules/layout.js | ||
---|---|---|
@@ -1,0 +1,21 @@ | ||
1 | +module.exports = { | |
2 | + needs: { inu: { html: 'first' } }, | |
3 | + create: (api) => (model, dispatch) => { | |
4 | + console.log('model', model) | |
5 | + const html = api.inu.html | |
6 | + return (view) => html` | |
7 | + <div> | |
8 | + <nav> | |
9 | + <a href='/'>home</a> | |
10 | + <a href=${`/cat/${randomId()}`}>a new cat!</a> | |
11 | + <a href='/nope'>nope</a> | |
12 | + </nav> | |
13 | + ${view} | |
14 | + </div> | |
15 | + ` | |
16 | + } | |
17 | +} | |
18 | + | |
19 | +function randomId () { | |
20 | + return Math.random().toString(8).substring(2) | |
21 | +} |
example/app/pages/home.js | ||
---|---|---|
@@ -1,0 +1,12 @@ | ||
1 | +module.exports = { | |
2 | + needs: { | |
3 | + inu: { html: 'first' }, | |
4 | + app: { modules: { layout: 'first' } } | |
5 | + }, | |
6 | + create: (api) => ({ | |
7 | + route: '/', | |
8 | + view: (model, dispatch) => api.app.modules.layout(model, dispatch)(api.inu.html` | |
9 | + <div>home!</div> | |
10 | + `) | |
11 | + }) | |
12 | +} |
example/cats/pages/one.js | ||
---|---|---|
@@ -1,0 +1,14 @@ | ||
1 | +const { get } = require('libnested') | |
2 | + | |
3 | +module.exports = { | |
4 | + needs: { | |
5 | + inu: { html: 'first' }, | |
6 | + app: { modules: { layout: 'first' } } | |
7 | + }, | |
8 | + create: (api) => ({ | |
9 | + route: '/cat/:catId', | |
10 | + view: (model, dispatch) => api.app.modules.layout(model, dispatch)(api.inu.html` | |
11 | + <div>one cat: ${model.router.params.catId}!</div> | |
12 | + `) | |
13 | + }) | |
14 | +} |
lib/app.js | ||
---|---|---|
@@ -1,0 +1,20 @@ | ||
1 | +const combine = require('depject') | |
2 | +const bulk = require('bulk-require') | |
3 | + | |
4 | +const mapModules = require('./mapModules') | |
5 | +const tranformModule = require('./transformModule') | |
6 | + | |
7 | +const types = require('../types') | |
8 | +const coreModules = require('../modules') | |
9 | + | |
10 | +module.exports = setupApp | |
11 | + | |
12 | +function setupApp ({ dirname } = {}) { | |
13 | + const appExports = bulk(dirname || process.cwd(), ['**/*.js'], { process }) | |
14 | + const appModules = mapModules(appExports, tranformModule(types)) | |
15 | + | |
16 | + return combine( | |
17 | + appModules, | |
18 | + coreModules | |
19 | + ) | |
20 | +} |
lib/mapModules.js | ||
---|---|---|
@@ -1,0 +1,26 @@ | ||
1 | +const { set } = require('libnested') | |
2 | +const isModule = require('depject/is') | |
3 | + | |
4 | +module.exports = mapModules | |
5 | + | |
6 | +function mapModules (obj, iter) { | |
7 | + var o = {} | |
8 | + eachModule(obj, (v, path) => { | |
9 | + set(o, path, iter(v, path)) | |
10 | + }) | |
11 | + return o | |
12 | +} | |
13 | + | |
14 | +function eachModule (obj, iter, path) { | |
15 | + path = path || [] | |
16 | + for (var k in obj) { | |
17 | + if (isObject(obj[k])) { | |
18 | + if (isModule(obj[k])) iter(obj[k], path.concat(k)) | |
19 | + else eachModule(obj[k], iter, path.concat(k)) | |
20 | + } | |
21 | + } | |
22 | +} | |
23 | + | |
24 | +function isObject (o) { | |
25 | + return o && 'object' === typeof o && !Array.isArray(o) | |
26 | +} |
lib/module.js | ||
---|---|---|
@@ -1,0 +1,19 @@ | ||
1 | +const { set } = require('libnested') | |
2 | + | |
3 | +module.exports = Module | |
4 | + | |
5 | +function Module (definition) { | |
6 | + const { path, gives, needs, create } = definition | |
7 | + var module = { gives, needs, create } | |
8 | + if (!gives) { | |
9 | + module.gives = {} | |
10 | + set(module.gives, path, true) | |
11 | + module.create = (api) => { | |
12 | + const exports = create(api) | |
13 | + var globalExports = {} | |
14 | + set(globalExports, path, exports) | |
15 | + return globalExports | |
16 | + } | |
17 | + } | |
18 | + return module | |
19 | +} |
lib/pathModule.js | ||
---|---|---|
@@ -1,0 +1,11 @@ | ||
1 | +const { join, basename, dirname, extname, sep } = require('path') | |
2 | +const assign = require('object-assign') | |
3 | + | |
4 | +module.exports = (definition, { filename }) => { | |
5 | + const path = join( | |
6 | + dirname(filename), | |
7 | + basename(filename, extname(filename)) | |
8 | + ).split(sep) | |
9 | + | |
10 | + return assign({ path }, definition) | |
11 | +} |
lib/readModules.js | ||
---|---|---|
@@ -1,0 +1,47 @@ | ||
1 | +// TODO extract into `bulk-require-async` | |
2 | +// and `bulkify-async` | |
3 | +// and `./lib/transformModule` | |
4 | + | |
5 | +const { assign, keys } = Object | |
6 | +const assert = require('assert') | |
7 | +const { join, sep } = require('path') | |
8 | +const readDirectory = require('read-directory') | |
9 | +const Matcher = require('minimatch').Minimatch | |
10 | +const requireFromString = require('require-from-string') | |
11 | +const mapValues = require('modify-values') | |
12 | + | |
13 | +module.exports = readModules | |
14 | + | |
15 | +function readModules (options, cb) { | |
16 | + const { dirname, types } = options | |
17 | + | |
18 | + // pre-compile type matchers | |
19 | + const matchers = mapValues(types, ({ glob }) => { | |
20 | + const matcher = Matcher(glob) | |
21 | + return filePath => matcher.match(filePath) | |
22 | + }) | |
23 | + | |
24 | + readDirectory(dirname, { | |
25 | + filter: '**/*.js', | |
26 | + dirnames: [dirname], | |
27 | + transform | |
28 | + }, cb) | |
29 | + | |
30 | + function transform (fileContent, parsedFilePath) { | |
31 | + const filePath = join(parsedFilePath.dir, parsedFilePath.base) | |
32 | + const path = join(parsedFilePath.dir, parsedFilePath.name).split(sep) | |
33 | + const exports = requireFromString(fileContent, filePath, { | |
34 | + appendPaths: [dirname] | |
35 | + }) | |
36 | + const module = assign({ path }, exports) | |
37 | + const modules = keys(types).reduce((sofar, typeName) => { | |
38 | + if (sofar !== null) return sofar | |
39 | + const { transform } = types[typeName] | |
40 | + const match = matchers[typeName] | |
41 | + return match(filePath) | |
42 | + ? transform(module) | |
43 | + : null | |
44 | + }, null) | |
45 | + return modules | |
46 | + } | |
47 | +} |
lib/readModules.test.js | ||
---|---|---|
@@ -1,0 +1,28 @@ | ||
1 | +const test = require('tape') | |
2 | +const { join } = require('path') | |
3 | + | |
4 | +const readModules = require('./readMdules') | |
5 | + | |
6 | +test('reads modules', t => { | |
7 | + getModules({ | |
8 | + dirname: join(__dirname, '../example'), | |
9 | + types: { | |
10 | + Page: { | |
11 | + transform: (module) => { | |
12 | + t.ok(module) | |
13 | + console.log('module', module) | |
14 | + return { | |
15 | + gives: module.path.join('/'), | |
16 | + create: () => () => module | |
17 | + } | |
18 | + }, | |
19 | + glob: '**/pages/*.js' | |
20 | + } | |
21 | + } | |
22 | + }, (err, modules) => { | |
23 | + t.error(err) | |
24 | + console.log('modules', modules) | |
25 | + t.ok(modules) | |
26 | + t.end() | |
27 | + }) | |
28 | +}) |
lib/scopeModule.js | ||
---|---|---|
@@ -1,0 +1,12 @@ | ||
1 | +const { basename, dirname, sep } = require('path') | |
2 | +const assign = require('object-assign') | |
3 | + | |
4 | +module.exports = (definition, { filename }) => { | |
5 | + const scope = dirname(filename).split(sep).slice(0, 1) | |
6 | + | |
7 | + return assign({}, definition, { | |
8 | + create: (api) => assign({ | |
9 | + scope | |
10 | + }, definition.create(api)) | |
11 | + }) | |
12 | +} |
lib/transformModule.js | ||
---|---|---|
@@ -1,0 +1,27 @@ | ||
1 | +const { keys, assign } = Object | |
2 | +const Matcher = require('minimatch').Minimatch | |
3 | +const mapValues = require('modify-values') | |
4 | + | |
5 | +module.exports = createModuleTransformer | |
6 | + | |
7 | +function createModuleTransformer (types) { | |
8 | + // pre-compile type matchers | |
9 | + const matchers = mapValues(types, ({ glob }) => { | |
10 | + const matcher = Matcher(glob) | |
11 | + return filename => matcher.match(filename) | |
12 | + }) | |
13 | + | |
14 | + return function transformModule (exports, path) { | |
15 | + const filename = path.join('/') + '.js' | |
16 | + const module = assign({ path }, exports) | |
17 | + const transformedModule = keys(types).reduce((sofar, typeName) => { | |
18 | + if (sofar !== null) return sofar | |
19 | + const { transform } = types[typeName] | |
20 | + const match = matchers[typeName] | |
21 | + return match(filename) | |
22 | + ? transform(module, { filename }) | |
23 | + : null | |
24 | + }, null) | |
25 | + return transformedModule | |
26 | + } | |
27 | +} |
modules/assets.js | ||
---|---|---|
@@ -1,0 +1,34 @@ | ||
1 | +const { join } = require('path') | |
2 | +const assets = require('vas-assets') | |
3 | + | |
4 | +module.exports = { | |
5 | + config: { | |
6 | + gives: { | |
7 | + config: { | |
8 | + vas: { | |
9 | + assets: { | |
10 | + entryFile: true, | |
11 | + js: true | |
12 | + } | |
13 | + } | |
14 | + } | |
15 | + }, | |
16 | + create: () => ({ | |
17 | + config: { | |
18 | + vas: { | |
19 | + assets: { | |
20 | + entryFile: () => join(__dirname, '../browserEntry.js'), | |
21 | + js: () => ({ | |
22 | + transform: [ | |
23 | + ['evalify', { files: ['**/service.js', '**/services/*.js'] } ], | |
24 | + ['bulkify', { vars: { dirname: undefined, process } } ], | |
25 | + 'es2040' | |
26 | + ] | |
27 | + }) | |
28 | + } | |
29 | + } | |
30 | + } | |
31 | + }) | |
32 | + }, | |
33 | + assets | |
34 | +} |
modules/http.js | ||
---|---|---|
@@ -1,0 +1,1 @@ | ||
1 | +module.exports = require('vas-http') |
modules/index.js | ||
---|---|---|
@@ -1,0 +1,3 @@ | ||
1 | +const bulk = require('bulk-require') | |
2 | + | |
3 | +module.exports = bulk(__dirname, ['!(index.js)']) |
modules/log.js | ||
---|---|---|
@@ -1,0 +1,4 @@ | ||
1 | +module.exports = { | |
2 | + core: require('catstack-log'), | |
3 | + store: require('inu-log') | |
4 | +} |
modules/router.js | ||
---|---|---|
@@ -1,0 +1,1 @@ | ||
1 | +module.exports = require('inu-router').modules.router |
modules/store.js | ||
---|---|---|
@@ -1,0 +1,1 @@ | ||
1 | +module.exports = require('inu/modules') |
server.js | ||
---|---|---|
@@ -1,0 +1,9 @@ | ||
1 | +const app = require('./lib/app') | |
2 | + | |
3 | +module.exports = startServer | |
4 | + | |
5 | +function startServer ({ cwd } = {}) { | |
6 | + const sockets = app({ cwd }) | |
7 | + console.log(sockets) | |
8 | + sockets.vas.start.map(s => s()) | |
9 | +} |
tmp.js | ||
---|---|---|
@@ -1,0 +1,5 @@ | ||
1 | +const bulk = require('bulk-require') | |
2 | + | |
3 | +const modules = bulk(process.cwd(), ['modules/*.js']) | |
4 | + | |
5 | +console.log(modules) |
types/Module.js | ||
---|---|---|
@@ -1,0 +1,12 @@ | ||
1 | +const pipe = require('value-pipe') | |
2 | + | |
3 | +const pathModule = require('../lib/pathModule') | |
4 | +const Module = require('../lib/module') | |
5 | + | |
6 | +module.exports = { | |
7 | + transform: pipe( | |
8 | + pathModule, | |
9 | + Module | |
10 | + ), | |
11 | + glob: '**/modules/*.js' | |
12 | +} |
types/Page.js | ||
---|---|---|
@@ -1,0 +1,6 @@ | ||
1 | +const Page = require('inu-router/Page') | |
2 | + | |
3 | +module.exports = { | |
4 | + transform: Page, | |
5 | + glob: '**/pages/*.js' | |
6 | +} |
types/State.js | ||
---|---|---|
@@ -1,0 +1,14 @@ | ||
1 | +const pipe = require('value-pipe') | |
2 | +const State = require('inu/state') | |
3 | + | |
4 | +const pathModule = require('../lib/pathModule') | |
5 | +const scopeModule = require('../lib/scopeModule') | |
6 | + | |
7 | +module.exports = { | |
8 | + transform: pipe( | |
9 | + pathModule, | |
10 | + scopeModule, | |
11 | + State | |
12 | + ), | |
13 | + glob: '**/state.js' | |
14 | +} |
Built with git-ssb-web