diff --git a/.editorconfig b/.editorconfig index a4e8f29c2..7352e894d 100644 --- a/.editorconfig +++ b/.editorconfig @@ -3,8 +3,13 @@ root = true [*] charset = utf-8 -[*.js] +[*.{js,json,yml,html,md}] indent_style = tab +tab_width = 4 trim_trailing_whitespace = true insert_final_newline = true end_of_line = lf + +[{package.json,.travis.yml}] +indent_style = space +indent_size = 2 diff --git a/.eslintignore b/.eslintignore index 62117a948..72bec5e8d 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,7 +1,7 @@ -.vscode/ -coverage/ -docs/lib/ -examples/ +/.vscode +/coverage +/docs/lib +/examples /mithril.js /mithril.min.js -node_modules/ +/node_modules diff --git a/.gitignore b/.gitignore index 13f89651b..aa4d28f32 100644 --- a/.gitignore +++ b/.gitignore @@ -6,5 +6,6 @@ npm-debug.log .DS_Store .eslintcache -# These are artifacts from Travis' deploy scripts +# These are artifacts from various scripts /dist +/archive diff --git a/.travis.yml b/.travis.yml index 181b73f3c..b04c360d9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,12 +16,6 @@ install: # This is to prevent lint-staged/prettier from running on the bundles - npm rm husky -# Build bundles (so they're always up to date) -before_script: -- npm run build-browser -# Pass -save so it'll update the readme as well -- npm run build-min -- -save - # Run tests, lint, and then check for perf regressions script: - npm test @@ -90,12 +84,13 @@ deploy: tags: true repo: MithrilJS/mithril.js - - provider: npm - skip_cleanup: true - email: me@isiahmeadows.com - api_key: - secure: "uPLbeJTalA/b38srb1VuWnD3eOgeKTkXf8VVUasUXIqc2xub4DSkFm1IVKSVd/rzP7EeO7+gRUs2UteNKlpZJl226IS5mFPSVtC7ViW46WSpYT0wlMsc7hrubMBGTx3/XYpPwtmMlTIGs5ICT7YkGAuju/6i79LDAB+gbnEY8Bc=" - on: - tags: true - repo: MithrilJS/mithril.js - condition: "$TRAVIS_TAG != *-*" + # Skip until I can figure out what's going on with docs + version deployment + # - provider: npm + # skip_cleanup: true + # email: me@isiahmeadows.com + # api_key: + # secure: "uPLbeJTalA/b38srb1VuWnD3eOgeKTkXf8VVUasUXIqc2xub4DSkFm1IVKSVd/rzP7EeO7+gRUs2UteNKlpZJl226IS5mFPSVtC7ViW46WSpYT0wlMsc7hrubMBGTx3/XYpPwtmMlTIGs5ICT7YkGAuju/6i79LDAB+gbnEY8Bc=" + # on: + # tags: true + # repo: MithrilJS/mithril.js + # condition: "$TRAVIS_TAG != *-*" diff --git a/docs/components.md b/docs/components.md index d564c42f5..88bd707ac 100644 --- a/docs/components.md +++ b/docs/components.md @@ -466,7 +466,7 @@ var Modal = { If you do it like above, you could run into issues when using it: -```js +```javascript var MyModal = { view: function() { return m(Modal, { @@ -483,7 +483,7 @@ var MyModal = { Instead, you should forward *single* attributes into vnodes: -```js +```javascript // PREFER var Modal = { // ... diff --git a/docs/generate.js b/docs/generate.js deleted file mode 100644 index 5650ae9da..000000000 --- a/docs/generate.js +++ /dev/null @@ -1,71 +0,0 @@ -"use strict" - -var fs = require("fs") -var path = require("path") -var marked = require("marked") -var layout = fs.readFileSync("./docs/layout.html", "utf-8") -var version = JSON.parse(fs.readFileSync("./package.json", "utf-8")).version -try {fs.mkdirSync("./dist")} catch (e) {/* ignore */} -try {fs.mkdirSync("./dist/archive")} catch (e) {/* ignore */} -try {fs.mkdirSync("./dist/archive/v" + version)} catch (e) {/* ignore */} - -var guides = fs.readFileSync("docs/nav-guides.md", "utf-8") -var methods = fs.readFileSync("docs/nav-methods.md", "utf-8") - -generate("docs") - -function generate(pathname) { - if (fs.lstatSync(pathname).isDirectory()) { - fs.readdirSync(pathname).forEach(function(filename) { - generate(pathname + "/" + filename) - }) - } - else if (!pathname.match(/tutorials|archive|nav-/)) { - if (pathname.match(/\.md$/)) { - var outputFilename = pathname.replace(/\.md$/, ".html") - var markdown = fs.readFileSync(pathname, "utf-8") - var anchors = {} - var fixed = markdown - .replace(/`((?:\S| -> |, )+)(\|)(\S+)`/gim, function(match, a, b, c) { // fix pipes in code tags - return "" + (a + b + c).replace(/\|/g, "|") + "" - }) - .replace(/(^# .+?(?:\r?\n){2,}?)(?:(-(?:.|\r|\n)+?)((?:\r?\n){2,})|)/m, function(match, title, nav) { // inject menu - var file = path.basename(pathname) - var link = new RegExp("([ \t]*)(- )(\\[.+?\\]\\(" + file + "\\))") - var replace = function(match, space, li, link) { - return space + li + "**" + link + "**" + (nav ? "\n" + nav.replace(/(^|\n)/g, "$1\t" + space) : "") - } - var modified = guides.match(link) ? guides.replace(link, replace) : methods.replace(link, replace) - return title + modified + "\n\n" - }) - .replace(/(\]\([^\)]+)(\.md)/gim, function(match, path, extension) { - return path + (path.match(/http/) ? extension : ".html") - }) // fix links - var markedHtml = marked(fixed) - .replace(/(\W)Array<([^/<]+?)>/gim, "$1Array<$2>") // Fix type signatures containing Array<...> - var title = fixed.match(/^#([^\n\r]+)/i) || [] - var html = layout - .replace(/Mithril\.js<\/title>/, "<title>" + title[1] + " - Mithril.js") - .replace(/\[version\]/g, version) // update version - .replace(/\[body\]/, markedHtml) - .replace(/(.+?)<\/h.>/gim, function(match, n, id, text) { // fix anchors - var anchor = text.toLowerCase().replace(/<(\/?)code>/g, "").replace(/.+?<\/a>/g, "").replace(/\.|\[|\]|"|\/|\(|\)/g, "").replace(/\s/g, "-"); - - if(anchor in anchors) { - anchor += ++anchors[anchor] - } else { - anchors[anchor] = 0; - } - - return `${text}`; - }) - fs.writeFileSync("./dist/archive/v" + version + "/" + outputFilename.replace(/^docs\//, ""), html, "utf-8") - fs.writeFileSync("./dist/" + outputFilename.replace(/^docs\//, ""), html, "utf-8") - } - else if (!pathname.match(/lint|generate/)) { - var encoding = (/\.(ico|png)$/i).test(path.extname(pathname)) ? "binary" : "utf-8"; - fs.writeFileSync("./dist/archive/v" + version + "/" + pathname.replace(/^docs\//, ""), fs.readFileSync(pathname, encoding), encoding) - fs.writeFileSync("./dist/" + pathname.replace(/^docs\//, ""), fs.readFileSync(pathname, encoding), encoding) - } - } -} diff --git a/docs/hyperscript.md b/docs/hyperscript.md index 731b5073d..2c70de2b0 100644 --- a/docs/hyperscript.md +++ b/docs/hyperscript.md @@ -215,7 +215,7 @@ m("a-scene", [ ]) ``` -And yes, this translates to both attributes and properties, and it works just like they would in the DOM. Using [Brick's `brick-deck`](https://brick.mozilla.io/docs/brick-deck) as an example, they have a `selected-index` attribute with a corresponding `selectedIndex` getter/setter property. +And yes, this translates to both attributes and properties, and it works just like they would in the DOM. Using [Brick's `brick-deck`](http://brick.mozilla.io/docs/brick-deck) as an example, they have a `selected-index` attribute with a corresponding `selectedIndex` getter/setter property. ```javascript m("brick-deck[selected-index=0]", [/* ... */]) // lowercase diff --git a/docs/installation.md b/docs/installation.md index 7ef19766b..16d70d650 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -51,7 +51,7 @@ $ npm install webpack webpack-cli --save-dev ``` 3. Add a "start" entry to the scripts section in `package.json`. -```js +```javascript { // ... "scripts": { @@ -61,7 +61,7 @@ $ npm install webpack webpack-cli --save-dev ``` 4. Create `src/index.js` file. -```js +```javascript import m from "mithril"; m.render(document.body, "hello world"); ``` @@ -113,7 +113,7 @@ m.render(document.body, "hello world") Modularization is the practice of separating the code into files. Doing so makes it easier to find code, understand what code relies on what code, and test. -CommonJS is a de-facto standard for modularizing JavaScript code, and it's used by Node.js, as well as tools like [Browserify](https://browserify.org/) and [Webpack](https://webpack.js.org/). It's a robust, battle-tested precursor to ES6 modules. Although the syntax for ES6 modules is specified in Ecmascript 6, the actual module loading mechanism is not. If you wish to use ES6 modules despite the non-standardized status of module loading, you can use tools like [Rollup](https://rollupjs.org/) or [Babel](https://babeljs.io/). +CommonJS is a de-facto standard for modularizing JavaScript code, and it's used by Node.js, as well as tools like [Browserify](http://browserify.org/) and [Webpack](https://webpack.js.org/). It's a robust, battle-tested precursor to ES6 modules. Although the syntax for ES6 modules is specified in Ecmascript 6, the actual module loading mechanism is not. If you wish to use ES6 modules despite the non-standardized status of module loading, you can use tools like [Rollup](https://rollupjs.org/) or [Babel](https://babeljs.io/). Most browser today do not natively support modularization systems (CommonJS or ES6), so modularized code must be bundled into a single JavaScript file before running in a client-side application. @@ -125,7 +125,7 @@ npm install webpack webpack-cli --save-dev Open the `package.json` that you created earlier, and add an entry to the `scripts` section: -``` +```json { "name": "my-project", "scripts": { @@ -199,7 +199,7 @@ If you open bin/app.js, you'll notice that the Webpack bundle is not minified, s You can use hooks in your production environment to run the production build script automatically. Here's an example for [Heroku](https://www.heroku.com/): -``` +```json { "name": "my-project", "scripts": { diff --git a/docs/jsx.md b/docs/jsx.md index 0142047b9..9806411b8 100644 --- a/docs/jsx.md +++ b/docs/jsx.md @@ -193,7 +193,7 @@ JSX and hyperscript are two different syntaxes you can use for specifying vnodes You can see the tradeoffs come into play in more complex trees. For instance, consider this hyperscript tree, adapted from a real-world project by [@isiahmeadows](https://github.com/isiahmeadows/) with some alterations for clarity and readability: -```js +```javascript function SummaryView() { let tag, posts diff --git a/docs/lint.js b/docs/lint.js deleted file mode 100644 index 356eb76a9..000000000 --- a/docs/lint.js +++ /dev/null @@ -1,186 +0,0 @@ -#!/usr/bin/env node -"use strict" - -var fs = require("fs") -var path = require("path") -var http = require("http") -var url = require("url") - -//lint rules -function lint(file, data) { - ensureCodeIsHighlightable(file, data) - ensureCodeIsSyntaticallyValid(file, data) - ensureCodeIsRunnable(file, data) - ensureCommentStyle(file, data) - ensureLinkIsValid(file, data) -} - -function ensureCodeIsHighlightable(file, data) { - var codeBlocks = data.match(/```(.|\n|\r)*?```/gim) || [] - codeBlocks.forEach(function(block) { - block = block.slice(3, -3) - if (block.indexOf("javascript") !== 0) { - try {if (new Function(block)) console.log(file + " - javascript block missing language tag after triple backtick\n\n" + block + "\n\n---\n\n")} - catch (e) {/*not a js block, ignore*/} - } - }) -} - -function ensureCodeIsSyntaticallyValid(file, data) { - var codeBlocks = data.match(/```javascript(.|\n|\r)*?```/gim) || [] - codeBlocks.forEach(function(block) { - block = block.slice(13, -3) - try {new Function(block)} - catch (e) {console.log(file + " - javascript block has wrong syntax\n\n" + e.message + "\n\n" + block + "\n\n---\n\n")} - }) -} - -function ensureCodeIsRunnable(file, data) { - var codeBlocks = data.match(/```javascript(.|\n|\r)*?```/gim) || [] - var code = codeBlocks.map(function(block) {return block.slice(13, -3)}).join(";") - - //stubs - var silentConsole = {log: function() {}} - var fetch = function() { - return Promise.resolve({ - json: function() {} - }) - } - - try { - initMocks() - var module = {exports: {}} - new Function("console,fetch,module,require", code).call(this, silentConsole, fetch, module, function(dep) { - if (dep.indexOf("./mycomponent") === 0) return {view: function() {}} - if (dep.indexOf("mithril/ospec/ospec") === 0) return global.o - if (dep.indexOf("mithril/stream") === 0) return global.stream - if (dep === "mithril") return global.m - - if (dep === "../model/User") return { - list: [], - current: {}, - loadList: function() { - return Promise.resolve({data: []}) - }, - load: function() { - return Promise.resolve({firstName: "", lastName: ""}) - }, - save: function() { - return Promise.resolve() - }, - } - if (dep === "./view/UserList") return {view: function() {}} - if (dep === "./view/UserForm") return {view: function() {}} - if (dep === "./view/Layout") return {view: function() {}} - }) - } - catch (e) {console.log(file + " - javascript code cannot run\n\n" + e.stack + "\n\n" + code + "\n\n---\n\n")} -} - -function ensureCommentStyle(file, data) { - var codeBlocks = data.match(/```javascript(.|\n|\r)*?```/gim) || [] - codeBlocks.forEach(function(block) { - block = block.slice(13, -3) - if (block.match(/(^|\s)\/\/[\S]/)) console.log(file + " - comment missing space\n\n" + block + "\n\n---\n\n") - }) -} - -function ensureLinkIsValid(file, data) { - var links = data.match(/\]\(([^\)]+?)\)/gim) || [] - links.forEach(function(match) { - var link = match.slice(2, -1) - var path = (link.match(/[\w-#]+\.md/) || [])[0] - if (link.match(/http/)) { - var u = url.parse(link) - http.request({method: "HEAD", host: u.host, path: u.pathname, port: 80}).on("error", function() { - console.log(file + " - broken external link: " + link) - }) - } - else if (path && !fs.existsSync("docs/" + path)) console.log(file + " - broken link: " + link) - }) -} - -function initMocks() { - /* eslint-disable global-require */ - global.window = require("../test-utils/browserMock")() - global.document = window.document - global.m = require("../index") - global.o = require("../ospec/ospec") - global.stream = require("../stream") - global.alert = function() {} - /* eslint-enable global-require */ - - //routes consumed by request.md - global.window.$defineRoutes({ - "GET /api/v1/users": function() { - return {status: 200, responseText: JSON.stringify([{name: ""}])} - }, - "GET /api/v1/users/search": function() { - return {status: 200, responseText: JSON.stringify([{id: 1, name: ""}])} - }, - "GET /api/v1/users/1/projects": function() { - return {status: 200, responseText: JSON.stringify([{id: 1, name: ""}])} - }, - "GET /api/v1/todos": function() { - return {status: 200, responseText: JSON.stringify([])} - }, - "PUT /api/v1/users/1": function(request) { - return {status: 200, responseText: request.query.callback ? request.query.callback + "([])" : "[]"} - }, - "POST /api/v1/upload": function() { - return {status: 200, responseText: JSON.stringify([])} - }, - "GET /files/icon.svg": function() { - return {status: 200, responseText: ""} - }, - "GET /files/data.csv": function() { - return {status: 200, responseText: "a,b,c"} - }, - "GET /api/v1/users/123": function() { - return {status: 200, responseText: JSON.stringify({id: 123})} - }, - "GET /api/v1/users/foo:bar": function() { - return {status: 200, responseText: JSON.stringify({id: 123})} - }, - "GET /files/image.svg": function() { - return {status: 200, responseText: ""} - }, - }) -} - -//runner -function traverseDirectory(pathname, callback) { - pathname = pathname.replace(/\\/g, "/") - return new Promise(function(resolve, reject) { - fs.lstat(pathname, function(err, stat) { - if (err) reject(err) - if (stat.isDirectory()) { - fs.readdir(pathname, function(err, pathnames) { - if (err) reject(err) - var promises = [] - for (var i = 0; i < pathnames.length; i++) { - pathnames[i] = path.join(pathname, pathnames[i]) - promises.push(traverseDirectory(pathnames[i], callback)) - } - callback(pathname, stat, pathnames) - resolve(Promise.all(promises)) - }) - } - else { - callback(pathname, stat) - resolve(pathname) - } - }) - }) -} - -//run -traverseDirectory("./docs", function(pathname) { - if (pathname.indexOf(".md") > -1 && !pathname.match(/change-log|migration-|node_modules/)) { - fs.readFile(pathname, "utf8", function(err, data) { - if (err) console.log(err) - else lint(pathname, data) - }) - } -}) - .then(process.exit) diff --git a/docs/migration-v02x.md b/docs/migration-v02x.md index ea441b6c0..5f52a2809 100644 --- a/docs/migration-v02x.md +++ b/docs/migration-v02x.md @@ -349,7 +349,7 @@ m("div", m(Component, "value", function(key) { return "child" })) In v0.2.x, the children of DOM nodes were represented literally with no normalization aside from using the children directly if only a single array child is present. It returned a structure more like this, with the strings represented literally. -```js +```javascript m("div", "value", ["nested"]) // Becomes: @@ -365,7 +365,7 @@ m("div", "value", ["nested"]) In v2.x, children of DOM vnodes are normalized to objects of a single consistent structure. -```js +```javascript m("div", "value", ["nested"]) // Becomes roughly: @@ -383,7 +383,7 @@ m("div", "value", ["nested"]) If only a single text child is present on a DOM vnode, it instead sets `text` to that value. -```js +```javascript m("div", "value") // Becomes roughly: diff --git a/docs/route.md b/docs/route.md index 0be4f415e..823ca82e2 100644 --- a/docs/route.md +++ b/docs/route.md @@ -177,7 +177,7 @@ m(m.route.Link, { }, "link name") ``` -This supports full accessibility for both `a` and `button`, via a `disabled` attribute. This ensures [no `href` attribute or `onclick` handler is set](https://css-tricks.com/how-to-disable-links/) and that an `"aria-disabled": "true"` attribute *is* set. If you are passing an `onclick` handler already, that's dropped. (You can work around this by adding it directly in a [lifecycle hook](lifecycle.md).) The `disabled` attribute is itself proxied to the element or component, so you can disable routed `