Repository: Raynos/main-loop
Branch: master
Commit: 0f539cd8a8ef
Files: 9
Total size: 12.1 KB
Directory structure:
gitextract_vgylkcq1/
├── .gitignore
├── .jshintrc
├── .travis.yml
├── LICENCE
├── README.md
├── docs.mli
├── index.js
├── package.json
└── test/
└── index.js
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
.DS_Store
.monitor
.*.swp
.nodemonignore
releases
*.log
*.err
fleet.json
public/browserify
bin/*.json
.bin
build
compile
.lock-wscript
coverage
node_modules
================================================
FILE: .jshintrc
================================================
{
"maxdepth": 4,
"maxstatements": 200,
"maxcomplexity": 12,
"maxlen": 80,
"maxparams": 5,
"curly": true,
"eqeqeq": true,
"immed": true,
"latedef": false,
"noarg": true,
"noempty": true,
"nonew": true,
"undef": true,
"unused": "vars",
"trailing": true,
"quotmark": true,
"expr": true,
"asi": true,
"browser": false,
"esnext": true,
"devel": false,
"node": false,
"nonstandard": false,
"predef": ["require", "module", "__dirname", "__filename"]
}
================================================
FILE: .travis.yml
================================================
language: node_js
node_js:
- 0.8
- "0.10"
before_script:
- npm install
- npm install istanbul coveralls
script: npm run travis-test
================================================
FILE: LICENCE
================================================
Copyright (c) 2014 Raynos.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
================================================
FILE: README.md
================================================
# main-loop
<!--
[![build status][1]][2]
[![NPM version][3]][4]
[![Coverage Status][5]][6]
[![gemnasium Dependency Status][7]][8]
[![Davis Dependency status][9]][10]
-->
<!-- [![browser support][11]][12] -->
A rendering loop for diffable UIs
`main-loop` is an optimization module for a virtual DOM system. Normally you would re-create the virtual tree every time your state changes. This is not optimum, with main-loop you will only update your virtual tree at most once per request animation frame.
`main-loop` basically gives you batching of your virtual DOM changes, which means if you change your model multiple times it will be rendered once asynchronously on the next request animation frame.
## Example
```js
var mainLoop = require("main-loop")
var h = require("virtual-dom/h")
var initState = { fruits: ["apple", "banana"], name: "Steve" }
function render(state) {
return h("div", [
h("div", [
h("span", "hello "),
h("span.name", state.name)
]),
h("ul", state.fruits.map(renderFruit))
])
function renderFruit(fruitName) {
return h("li", [
h("span", fruitName)
])
}
}
// set up a loop
var loop = mainLoop(initState, render, {
create: require("virtual-dom/create-element"),
diff: require("virtual-dom/diff"),
patch: require("virtual-dom/patch")
})
document.body.appendChild(loop.target)
// update the loop with the new application state
loop.update({
fruits: ["apple", "banana", "cherry"],
name: "Steve"
})
loop.update({
fruits: ["apple", "banana", "cherry"],
name: "Stevie"
})
```
## var loop = mainLoop(initState, render, opts)
Create a loop object with some initial state, a render function, and some
options. Your `function render (state) {}` receives the current state as its
argument and must return a virtual-dom object.
You must supply: `opts.diff`, `opts.patch`, and `opts.create`. These can be
obtained directly from `require("virtual-dom")`.
Optionally supply an `opts.target` and `opts.initialTree`.
## loop.target
The main-loop root DOM element. Insert this element to the page.
## loop.update(newState)
Update the page state, automatically re-rendering the page as necessary.
## loop.state
Read the current main-loop state. To modify the loop state, use `loop.update()`.
## Installation
`npm install main-loop`
## Contributors
- Raynos
## MIT Licenced
[1]: https://secure.travis-ci.org/Raynos/main-loop.png
[2]: https://travis-ci.org/Raynos/main-loop
[3]: https://badge.fury.io/js/main-loop.png
[4]: https://badge.fury.io/js/main-loop
[5]: https://coveralls.io/repos/Raynos/main-loop/badge.png
[6]: https://coveralls.io/r/Raynos/main-loop
[7]: https://gemnasium.com/Raynos/main-loop.png
[8]: https://gemnasium.com/Raynos/main-loop
[9]: https://david-dm.org/Raynos/main-loop.png
[10]: https://david-dm.org/Raynos/main-loop
[11]: https://ci.testling.com/Raynos/main-loop.png
[12]: https://ci.testling.com/Raynos/main-loop
================================================
FILE: docs.mli
================================================
import { VElem, VPatch } from "vtree"
import { DOMElement } from "jsig.dom"
type MainLoop<T> : (
initialState: T,
view: (T) => VElem,
opts?: {
create?: (VElem, opts: Object) => DOMElement,
diff?: (prev: VElem, curr: VElem, opts: Object) => Array<VPatch>,
patch?: (
target: DOMElement,
patches: Array<VPatch>,
opts: Object
) => void,
initialTree?: VElem,
target?: DOMElement,
createOnly?: Boolean
}
) => {
target: DOMElement,
update: (T) => void
}
main-loop : MainLoop<T>
================================================
FILE: index.js
================================================
var raf = require("raf")
var TypedError = require("error/typed")
var InvalidUpdateInRender = TypedError({
type: "main-loop.invalid.update.in-render",
message: "main-loop: Unexpected update occurred in loop.\n" +
"We are currently rendering a view, " +
"you can't change state right now.\n" +
"The diff is: {stringDiff}.\n" +
"SUGGESTED FIX: find the state mutation in your view " +
"or rendering function and remove it.\n" +
"The view should not have any side effects.\n" +
"This may also have happened if rendering did not complete due to an error.\n",
diff: null,
stringDiff: null
})
module.exports = main
function main(initialState, view, opts) {
opts = opts || {}
var currentState = initialState
var create = opts.create
var diff = opts.diff
var patch = opts.patch
var redrawScheduled = false
var tree = opts.initialTree || view(currentState, 0);
var target = opts.target || create(tree, opts)
var inRenderingTransaction = false
currentState = null
var loop = {
state: initialState,
target: target,
update: update
}
return loop
function update(state) {
if (inRenderingTransaction) {
throw InvalidUpdateInRender({
diff: state._diff,
stringDiff: JSON.stringify(state._diff)
})
}
if (currentState === null && !redrawScheduled) {
redrawScheduled = true
raf(redraw)
}
currentState = state
loop.state = state
}
function redraw(time) {
redrawScheduled = false
if (currentState === null) {
return
}
inRenderingTransaction = true
var newTree = view(currentState, time)
if (opts.createOnly) {
inRenderingTransaction = false
create(newTree, opts)
} else {
var patches = diff(tree, newTree, opts)
inRenderingTransaction = false
target = patch(target, patches, opts)
}
tree = newTree
currentState = null
}
}
================================================
FILE: package.json
================================================
{
"name": "main-loop",
"version": "3.4.0",
"description": "A rendering loop for diffable UIs",
"keywords": [],
"author": "Raynos <raynos2@gmail.com>",
"repository": "git://github.com/Raynos/main-loop.git",
"main": "index",
"homepage": "https://github.com/Raynos/main-loop",
"contributors": [
{
"name": "Raynos"
}
],
"bugs": {
"url": "https://github.com/Raynos/main-loop/issues",
"email": "raynos2@gmail.com"
},
"dependencies": {
"error": "^4.1.1",
"raf": "^2.0.1"
},
"devDependencies": {
"global": "^3.0.0",
"istanbul": "^0.3.0",
"tape": "^2.13.3",
"virtual-dom": "0.0.23"
},
"licenses": [
{
"type": "MIT",
"url": "http://github.com/Raynos/main-loop/raw/master/LICENSE"
}
],
"scripts": {
"test": "node ./test/index.js",
"start": "node ./index.js",
"watch": "nodemon -w ./index.js index.js",
"travis-test": "istanbul cover ./test/index.js && ((cat coverage/lcov.info | coveralls) || exit 0)",
"cover": "istanbul cover --report none --print detail ./test/index.js",
"view-cover": "istanbul report html && google-chrome ./coverage/index.html",
"test-browser": "testem-browser ./test/browser/index.js",
"testem": "testem-both -b=./test/browser/index.js"
},
"testling": {
"files": "test/index.js",
"browsers": [
"ie/8..latest",
"firefox/16..latest",
"firefox/nightly",
"chrome/22..latest",
"chrome/canary",
"opera/12..latest",
"opera/next",
"safari/5.1..latest",
"ipad/6.0..latest",
"iphone/6.0..latest",
"android-browser/4.2..latest"
]
}
}
================================================
FILE: test/index.js
================================================
var test = require("tape")
var h = require("virtual-dom/virtual-hyperscript")
var document = require("global/document")
var raf = require("raf")
var mainLoop = require("../index")
test("mainLoop is a function", function (assert) {
assert.equal(typeof mainLoop, "function")
assert.end()
})
test("can set up main loop", function (assert) {
var initState = { fruits: ["apple", "banana"], name: "Steve" }
function render(state) {
return h("div", [
h("div", [
h("span", "hello "),
h("span.name", state.name)
]),
h("ul", state.fruits.map(renderFruit))
])
function renderFruit(fruitName) {
return h("li", [
h("span", fruitName)
])
}
}
// set up a loop
var loop = mainLoop(initState, render, {
document: document,
create: require("virtual-dom/create-element"),
diff: require("virtual-dom/diff"),
patch: require("virtual-dom/patch")
})
document.body.appendChild(loop.target)
var div = loop.target
var span = div.childNodes[0].childNodes[1]
var ul = div.childNodes[1]
assert.equal(div.tagName, "DIV")
assert.equal(span.childNodes[0].data, "Steve")
assert.equal(ul.childNodes.length, 2)
// update the loop with the new application state
loop.update({
fruits: ["apple", "banana", "cherry"],
name: "Steve"
})
raf(function () {
assert.equal(ul.childNodes.length, 3)
loop.update({
fruits: ["apple", "banana", "cherry"],
name: "Stevie"
})
raf(function () {
assert.equal(span.childNodes[0].data, "Stevie")
document.body.removeChild(loop.target)
assert.end()
})
})
})
test("loop.state exposed", function (assert) {
var loop = mainLoop({ n: 0 }, render, {
document: document,
create: require("virtual-dom/create-element"),
diff: require("virtual-dom/diff"),
patch: require("virtual-dom/patch")
})
assert.equal(loop.state.n, 0)
loop.update({ n: 4 })
assert.equal(loop.state.n, 4)
assert.end()
function render(state) {
return h('div', String(state.n))
}
})
test("render called with monotonically increasing times", function(assert){
assert.plan(2)
var times = []
var loop = mainLoop({ n: 0 }, render, {
document: document,
create: require("virtual-dom/create-element"),
diff: require("virtual-dom/diff"),
patch: require("virtual-dom/patch")
})
function render(state, time) {
times.push(time);
return h('div', String(state.n))
}
raf(function () {
loop.update({ n: 1})
raf(function () {
loop.update({ n: 2})
assert.equal(times.length, 2)
assert.ok(times[0] < times[1], "should be increasing")
assert.end()
})
})
});
gitextract_vgylkcq1/
├── .gitignore
├── .jshintrc
├── .travis.yml
├── LICENCE
├── README.md
├── docs.mli
├── index.js
├── package.json
└── test/
└── index.js
SYMBOL INDEX (4 symbols across 2 files)
FILE: index.js
function main (line 20) | function main(initialState, view, opts) {
FILE: test/index.js
function render (line 16) | function render(state) {
function render (line 84) | function render(state) {
function render (line 101) | function render(state, time) {
Condensed preview — 9 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (14K chars).
[
{
"path": ".gitignore",
"chars": 157,
"preview": ".DS_Store\n.monitor\n.*.swp\n.nodemonignore\nreleases\n*.log\n*.err\nfleet.json\npublic/browserify\nbin/*.json\n.bin\nbuild\ncompile"
},
{
"path": ".jshintrc",
"chars": 545,
"preview": "{\n \"maxdepth\": 4,\n \"maxstatements\": 200,\n \"maxcomplexity\": 12,\n \"maxlen\": 80,\n \"maxparams\": 5,\n\n \"curl"
},
{
"path": ".travis.yml",
"chars": 138,
"preview": "language: node_js\nnode_js:\n - 0.8\n - \"0.10\"\nbefore_script:\n - npm install\n - npm install istanbul coveralls\nscript: np"
},
{
"path": "LICENCE",
"chars": 1051,
"preview": "Copyright (c) 2014 Raynos.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this softwar"
},
{
"path": "README.md",
"chars": 3033,
"preview": "# main-loop\n\n<!--\n [![build status][1]][2]\n [![NPM version][3]][4]\n [![Coverage Status][5]][6]\n [![gemnasium"
},
{
"path": "docs.mli",
"chars": 589,
"preview": "import { VElem, VPatch } from \"vtree\"\nimport { DOMElement } from \"jsig.dom\"\n\ntype MainLoop<T> : (\n initialState: T,\n "
},
{
"path": "index.js",
"chars": 2165,
"preview": "var raf = require(\"raf\")\nvar TypedError = require(\"error/typed\")\n\nvar InvalidUpdateInRender = TypedError({\n type: \"ma"
},
{
"path": "package.json",
"chars": 1656,
"preview": "{\n \"name\": \"main-loop\",\n \"version\": \"3.4.0\",\n \"description\": \"A rendering loop for diffable UIs\",\n \"keywords\": [],\n "
},
{
"path": "test/index.js",
"chars": 3009,
"preview": "var test = require(\"tape\")\nvar h = require(\"virtual-dom/virtual-hyperscript\")\nvar document = require(\"global/document\")\n"
}
]
About this extraction
This page contains the full source code of the Raynos/main-loop GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 9 files (12.1 KB), approximately 3.4k tokens, and a symbol index with 4 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.