diff --git a/.editorconfig b/.editorconfig index 7352e894d..7f44b1db8 100644 --- a/.editorconfig +++ b/.editorconfig @@ -10,6 +10,6 @@ trim_trailing_whitespace = true insert_final_newline = true end_of_line = lf -[{package.json,.travis.yml}] +[{package.json,.travis.yml,.github/**/*.yml}] indent_style = space indent_size = 2 diff --git a/.gitattributes b/.gitattributes index bc1c2b0db..af779b11a 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,8 +1,6 @@ * text=auto /mithril.js binary /mithril.min.js binary -/package-lock.json binary -/yarn.lock binary # Assets *.png binary diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index bb541ea7e..6988722d6 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1,2 @@ -* @dead-claudia @StephanHoyer +* @MithrilJS/Committers +/.github/ @MithrilJS/Admins diff --git a/.github/ISSUE_TEMPLATE/0-docs.yml b/.github/ISSUE_TEMPLATE/0-docs.yml new file mode 100644 index 000000000..964a2b689 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/0-docs.yml @@ -0,0 +1,26 @@ +name: '📃 Documentation Issue' +description: Report an issue with Mithril.js's documentation +assignees: dead-claudia +labels: +- 'Area: Documentation' +body: +- type: checkboxes + attributes: + label: Is there an existing issue for this? + description: Please search to see if an issue already exists for the bug you encountered. + options: + - label: I have searched the existing issues + required: true +- type: input + attributes: + label: Offending URL + description: Provide a link to the page with the issue + placeholder: https://mithril.js.org/ + validations: + required: true +- type: textarea + attributes: + label: Issue description + description: What is the precise issue with it. Please be specific. + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/1-core.yml b/.github/ISSUE_TEMPLATE/1-core.yml new file mode 100644 index 000000000..bd1cc4fca --- /dev/null +++ b/.github/ISSUE_TEMPLATE/1-core.yml @@ -0,0 +1,117 @@ +name: '🐛 Framework Bug' +description: Report a bug in Mithril.js core +assignees: dead-claudia +labels: +- 'Area: Core' +body: +- type: checkboxes + attributes: + label: Is there an existing issue for this? + description: Please search to see if an issue already exists for the bug you encountered. + options: + - label: I have searched the existing issues + required: true +- type: input + attributes: + label: Mithril.js Version + description: | + Provide the exact version of Mithril.js you're experiencing these issues with. This + matters, even if it's really old like version 0.1.0. Do note that bugs in older + versions are commonly fixed in newer versions, so you should try to test it + against the latest version if you can. + validations: + required: true +- type: textarea + attributes: + label: Browser and OS + description: | + Provide the name and version of both the browser and operating system you're + experiencing these issues with. If it's multiple, feel free to list multiple. + This matters, even if it's super ancient. + validations: + required: true +- type: textarea + attributes: + label: Project + description: | + (Optional) Provide a link to your project, if it happens to be open source or if + you created a repo somewhere that we can look into further. If it's spread across + multiple repos or projects, feel free to list them all. +- type: textarea + attributes: + label: Code + description: | + What did you try? What code is causing the unexpected behavior? Make sure to + try to reduce your code as best as you can while still reproducing the bug, so + we can more accurately determine the cause. Ideally, it should just be a bunch + of Mithril.js calls with virtually no logic at all, but it's sufficient to just + remove unrelated network calls, attributes, and the like. + + In addition, make sure the bug still persists with the latest version of + Mithril. If it's an older version, the bug may have already been fixed. + + If you'd prefer, replace this code block with a link to a code playground like + any of these: + + - Flems (stores everything in URL hash) + - JSFiddle + - CodePen + - JSBin + - Plunker + - Glitch (supports backend) + - CodeSandbox (supports backend) + + Or if it's a remote development project on your own server, feel free to provide + that if it's serving unminified code we can look at. + + If it's a closed-source repo, it's okay to censor names and pull out irrelevant + logic - we'd rather not sign NDAs just to see the code you're having trouble + with. We do still need code of some kind that triggers the bug you're running + into. + render: javascript + validations: + required: true +- type: textarea + attributes: + label: Steps to Reproduce + description: | + What steps need to be taken to reproduce this behavior? Please include things + like specific data that need typed in, specific buttons that need clicked, and + so on. + placeholder: | + 1. + 2. + 3. + 4. + validations: + required: true +- type: textarea + attributes: + label: Expected Behavior + description: | + What did you expect to happen? + + - An alert to pop up? + - A specific thing to be logged? + + Please be very specific here. + validations: + required: true +- type: textarea + attributes: + label: Observed Behavior + description: | + What actually happened? + + - The alert never showed? + - The wrong thing was logged? + + Please be very specific here. + validations: + required: true +- type: textarea + attributes: + label: Context + description: | + (Optional) How is this issue affecting you? What are you trying to do? Providing + us context helps us reach a solution that best fits your particular needs. diff --git a/.github/ISSUE_TEMPLATE/2-stream.yml b/.github/ISSUE_TEMPLATE/2-stream.yml new file mode 100644 index 000000000..2434524b5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/2-stream.yml @@ -0,0 +1,117 @@ +name: '🌊 Mithril.js Streams bug' +description: Report an issue with Mithril.js's Streams module +assignees: dead-claudia +labels: +- 'Area: Stream' +body: +- type: checkboxes + attributes: + label: Is there an existing issue for this? + description: Please search to see if an issue already exists for the bug you encountered. + options: + - label: I have searched the existing issues + required: true +- type: input + attributes: + label: Mithril.js Version + description: | + Provide the exact version of Mithril.js you're experiencing these issues with. This + matters, even if it's really old like version 0.1.0. Do note that bugs in older + versions are commonly fixed in newer versions, so you should try to test it + against the latest version if you can. + validations: + required: true +- type: textarea + attributes: + label: Browser and OS + description: | + Provide the name and version of both the browser and operating system you're + experiencing these issues with. If it's multiple, feel free to list multiple. + This matters, even if it's super ancient. + validations: + required: true +- type: textarea + attributes: + label: Project + description: | + (Optional) Provide a link to your project, if it happens to be open source or if + you created a repo somewhere that we can look into further. If it's spread across + multiple repos or projects, feel free to list them all. +- type: textarea + attributes: + label: Code + description: | + What did you try? What code is causing the unexpected behavior? Make sure to + try to reduce your code as best as you can while still reproducing the bug, so + we can more accurately determine the cause. Ideally, it should just be a bunch + of Mithril.js calls with virtually no logic at all, but it's sufficient to just + remove unrelated network calls, attributes, and the like. + + In addition, make sure the bug still persists with the latest version of + Mithril. If it's an older version, the bug may have already been fixed. + + If you'd prefer, replace this code block with a link to a code playground like + any of these: + + - Flems (stores everything in URL hash) + - JSFiddle + - CodePen + - JSBin + - Plunker + - Glitch (supports backend) + - CodeSandbox (supports backend) + + Or if it's a remote development project on your own server, feel free to provide + that if it's serving unminified code we can look at. + + If it's a closed-source repo, it's okay to censor names and pull out irrelevant + logic - we'd rather not sign NDAs just to see the code you're having trouble + with. We do still need code of some kind that triggers the bug you're running + into. + render: javascript + validations: + required: true +- type: textarea + attributes: + label: Steps to Reproduce + description: | + What steps need to be taken to reproduce this behavior? Please include things + like specific data that need typed in, specific buttons that need clicked, and + so on. + placeholder: | + 1. + 2. + 3. + 4. + validations: + required: true +- type: textarea + attributes: + label: Expected Behavior + description: | + What did you expect to happen? + + - An alert to pop up? + - A specific thing to be logged? + + Please be very specific here. + validations: + required: true +- type: textarea + attributes: + label: Observed Behavior + description: | + What actually happened? + + - The alert never showed? + - The wrong thing was logged? + + Please be very specific here. + validations: + required: true +- type: textarea + attributes: + label: Context + description: | + (Optional) How is this issue affecting you? What are you trying to do? Providing + us context helps us reach a solution that best fits your particular needs. diff --git a/.github/ISSUE_TEMPLATE/bug.md b/.github/ISSUE_TEMPLATE/bug.md deleted file mode 100644 index 35db54630..000000000 --- a/.github/ISSUE_TEMPLATE/bug.md +++ /dev/null @@ -1,102 +0,0 @@ ---- -name: "\U0001F41B Bug" -about: Report a bug in Mithril.js -title: '' -labels: 'Type: Bug' -assignees: dead-claudia - ---- - - - -**Mithril.js version:** - - -**Browser and OS:** - - -**Project:** - -## Code - -```javascript -// Code -``` - -## Steps to Reproduce - -1. -2. -3. -4. - -## Expected Behavior - - -## Current Behavior - - -## Context - diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 000000000..425bfdba0 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,18 @@ +blank_issues_enabled: true +contact_links: + - name: ℹ Questions, Ideas, and Discussions + url: https://github.com/MithrilJS/mithril.js/discussions + about: | + Got a question on how to use Mithril.js? Have a fancy idea of how we could do better? Check + out our discussions forum! + - name: ℹ Show and Tell + url: https://github.com/MithrilJS/mithril.js/discussions/new?category=show-and-tell + about: | + Got something to show off? Made something so cool, you just have to tell the world? Let us + know here in our discussions forum! + - name: 🚀 Feature Request or Enhancement + url: https://github.com/MithrilJS/mithril.js/discussions/new?category=ideas + about: Got a feature request? Let us know here! We do those in our discussion forum. + - name: 💻 Zulip Chat + url: https://mithril.zulipchat.com/ + about: Not sure about something? Just want to hang out? Come over to our Zulip chat! diff --git a/.github/ISSUE_TEMPLATE/feature-or-enhancement.md b/.github/ISSUE_TEMPLATE/feature-or-enhancement.md deleted file mode 100644 index 81df37660..000000000 --- a/.github/ISSUE_TEMPLATE/feature-or-enhancement.md +++ /dev/null @@ -1,72 +0,0 @@ ---- -name: "\U0001F680 Feature or Enhancement" -about: Suggest an idea or feature for Mithril.js -title: '' -labels: 'Type: Enhancement' -assignees: dead-claudia - ---- - - - -**Mithril.js version:** - - -**Platform and OS:** - - -**Project:** - - -**Is this something you're interested in implementing yourself?** - -### Description - - -### Why - - -### Possible Implementation - - -### Open Questions - diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md deleted file mode 100644 index 45b04f73f..000000000 --- a/.github/ISSUE_TEMPLATE/question.md +++ /dev/null @@ -1,82 +0,0 @@ ---- -name: "\U0001F64B‍♀️ Question" -about: Ask a question about Mithril.js -title: '' -labels: 'Type: Question' -assignees: '' - ---- - - - -**Mithril.js version:** - - -**Browser and OS:** - - -**Project:** - -## Code - -```javascript -// Code -``` - -## Expected Behavior - - -## Current Behavior - - -## Steps to Reproduce - -1. -2. -3. -4. - -## Context - diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..298ad7080 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,25 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file + +version: 2 +updates: + - package-ecosystem: "npm" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: daily + groups: + version-updates: + applies-to: version-updates + security-updates: + applies-to: security-updates + - package-ecosystem: github-actions + directory: / + schedule: + interval: daily + groups: + security: + applies-to: security-updates + normal: + applies-to: version-updates diff --git a/.github/workflows/_npm-task.yml b/.github/workflows/_npm-task.yml new file mode 100644 index 000000000..3ca12b2a6 --- /dev/null +++ b/.github/workflows/_npm-task.yml @@ -0,0 +1,35 @@ +name: Run npm task + +on: + workflow_call: + inputs: + task: + type: string + required: true + node-version: + type: number + default: 20 + continue-on-error: + type: boolean + default: false + +permissions: + contents: read + +# This uses actions/checkout instead of `git clone` directly since it's way +# easier than parsing everything out. + +jobs: + run-task: + name: npm run ${{ inputs.task }} + continue-on-error: ${{ inputs.continue-on-error }} + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 1 + - uses: actions/setup-node@v4 + with: + node-version: ${{ inputs.node-version }} + - run: npm ci + - run: npm run ${{ inputs.task }} diff --git a/.github/workflows/_post-comment.yml b/.github/workflows/_post-comment.yml new file mode 100644 index 000000000..103dd569d --- /dev/null +++ b/.github/workflows/_post-comment.yml @@ -0,0 +1,23 @@ +name: Post comment + +on: + workflow_call: + inputs: + url: + type: string + required: true + message: + type: string + required: true + +jobs: + notify: + runs-on: ubuntu-latest + steps: + - run: | + export GITHUB_TOKEN="$GH_TOKEN_SECRET" + gh issue comment "$ISSUE_URL" --body "$MESSAGE" + env: + ISSUE_URL: ${{ inputs.url }} + MESSAGE: ${{ inputs.message }} + GH_TOKEN_SECRET: ${{ github.token }} diff --git a/.github/workflows/auto-merge.yml b/.github/workflows/auto-merge.yml deleted file mode 100644 index 6708adcea..000000000 --- a/.github/workflows/auto-merge.yml +++ /dev/null @@ -1,16 +0,0 @@ -name: auto-merge - -on: - pull_request_target: - branches: [ next ] - -jobs: - auto-merge: - runs-on: ubuntu-latest - if: github.actor == 'dependabot[bot]' - steps: - - uses: actions/checkout@v3 - - uses: ahmadnassri/action-dependabot-auto-merge@v2 - with: - target: patch - github-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/issue-create.yml b/.github/workflows/issue-create.yml new file mode 100644 index 000000000..8735af936 --- /dev/null +++ b/.github/workflows/issue-create.yml @@ -0,0 +1,21 @@ +name: Ping triage on issue create +on: + issues: + types: [opened] +permissions: + issues: write + repository-projects: write +jobs: + add_triage: + runs-on: ubuntu-latest + steps: + - run: gh issue edit "$ISSUE_URL" --add-project 'Triage/bugs' + env: + ISSUE_URL: ${{ github.event.issue.url }} + GITHUB_TOKEN: ${{ github.token }} + + notify: + uses: ./.github/workflows/_post-comment.yml + with: + url: ${{ github.event.issue.url }} + message: '@MithrilJS/triage Please take a look.' diff --git a/.github/workflows/lint-docs.yml b/.github/workflows/lint-docs.yml deleted file mode 100644 index b4caf303b..000000000 --- a/.github/workflows/lint-docs.yml +++ /dev/null @@ -1,30 +0,0 @@ -# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node -# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions - -name: lint-docs - -on: - push: - branches: [ next ] - pull_request: - branches: [ next ] - -jobs: - lint-docs: - - runs-on: ubuntu-latest - - strategy: - matrix: - node-version: [18] - # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ - - steps: - - uses: actions/checkout@v3 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node-version }} - cache: 'npm' - - run: npm ci - - run: npm run lint:docs diff --git a/.github/workflows/lint-js.yml b/.github/workflows/lint-js.yml deleted file mode 100644 index 6aca83a15..000000000 --- a/.github/workflows/lint-js.yml +++ /dev/null @@ -1,30 +0,0 @@ -# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node -# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions - -name: lint-js - -on: - push: - branches: [ next ] - pull_request: - branches: [ next ] - -jobs: - lint-js: - - runs-on: ubuntu-latest - - strategy: - matrix: - node-version: [18] - # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ - - steps: - - uses: actions/checkout@v3 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node-version }} - cache: 'npm' - - run: npm ci - - run: npm run lint:js diff --git a/.github/workflows/merge.yml b/.github/workflows/merge.yml index 4b23a53d7..da6b1826e 100644 --- a/.github/workflows/merge.yml +++ b/.github/workflows/merge.yml @@ -2,7 +2,7 @@ name: merge on: push: - branches: [ master ] + branches: [ main ] workflow_dispatch: @@ -10,27 +10,18 @@ concurrency: prr:deploy jobs: merge: - runs-on: ubuntu-latest - strategy: - matrix: - node-version: [16.x] - steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: - ref: 'next' - fetch-depth: 0 - - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + ref: next + - uses: actions/setup-node@v4 with: - node-version: ${{ matrix.node-version }} - cache: 'npm' + node-version: 20 - run: npm ci - run: npm run build - - run: npx pr-release merge --target master --source next --commit --force --clean --changelog ./docs/recent-changes.md --compact --minimize-semver-change + - run: npx pr-release merge --target main --source next --commit --force --clean --changelog ./docs/recent-changes.md --compact --minimize-semver-change env: GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index f09b75bab..7fd5bdd22 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -10,23 +10,16 @@ concurrency: prr:pre-release jobs: pr: - runs-on: ubuntu-latest - strategy: - matrix: - node-version: [16.x] - steps: - - uses: actions/checkout@v3 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 with: - node-version: ${{ matrix.node-version }} - cache: 'npm' + node-version: 20 - run: npm ci - run: npm run build - - run: npx pr-release pr --verbose --target master --source next --compact --verbose --minimize-semver-change + - run: npx pr-release pr --verbose --target main --source next --compact --verbose --minimize-semver-change env: GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} # The following will publish a prerelease to npm @@ -34,5 +27,5 @@ jobs: name: Setup NPM Auth env: NPM_TOKEN: ${{ secrets.NPM_TOKEN }} - - run: npx pr-release infer-prerelease --preid=next --target master --source next --verbose --publish --minimize-semver-change + - run: npx pr-release infer-prerelease --preid=next --target main --source next --verbose --publish --minimize-semver-change name: Publish diff --git a/.github/workflows/push-master.yml b/.github/workflows/push-master.yml index 77bb6b87a..9b95880c2 100644 --- a/.github/workflows/push-master.yml +++ b/.github/workflows/push-master.yml @@ -1,19 +1,13 @@ -name: 'Push `master`' +name: Warn on pushing to `master` on: pull_request: types: [opened] - branches: ['master'] + branches: [master] +permissions: + issues: write jobs: comment: - runs-on: ubuntu-latest - steps: - - uses: actions/github-script@v3 - with: - github-token: ${{secrets.GITHUB_TOKEN}} - script: | - await github.issues.createComment({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - body: `⚠⚠⚠ Hey @${context.actor}, did you mean to open this against \`next\`? ⚠⚠⚠` - }) + uses: ./.github/workflows/_post-comment.yml + with: + url: ${{ github.event.pull_request.url }} + message: ⚠⚠⚠ Hey @${{ github.actor }}, did you mean to open this against `next`? ⚠⚠⚠ diff --git a/.github/workflows/rollback.yml b/.github/workflows/rollback.yml index f3c734765..eb2d5fd1c 100644 --- a/.github/workflows/rollback.yml +++ b/.github/workflows/rollback.yml @@ -7,23 +7,13 @@ concurrency: prr:deploy jobs: pr: - runs-on: ubuntu-latest - strategy: - matrix: - node-version: [16.x] - steps: - - uses: actions/checkout@v3 - with: - ref: 'next' - fetch-depth: 0 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 with: - node-version: ${{ matrix.node-version }} - cache: 'npm' + node-version: 20 - run: npm ci - run: npm run build - run: npx pr-release rollback --verbose --target master --source next --verbose --ignore 'package*' --ignore docs/changelog.md --ignore docs/recent-changes.md diff --git a/.github/workflows/test-js.yml b/.github/workflows/test-js.yml deleted file mode 100644 index 18b38822c..000000000 --- a/.github/workflows/test-js.yml +++ /dev/null @@ -1,30 +0,0 @@ -# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node -# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions - -name: test-js - -on: - push: - branches: [ next ] - pull_request: - branches: [ next ] - -jobs: - test-js: - - runs-on: ubuntu-latest - - strategy: - matrix: - node-version: [14, 16, 18] - # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ - - steps: - - uses: actions/checkout@v3 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node-version }} - cache: 'npm' - - run: npm ci - - run: npm run test:js diff --git a/.github/workflows/test-next-push.yml b/.github/workflows/test-next-push.yml new file mode 100644 index 000000000..3aaec97b0 --- /dev/null +++ b/.github/workflows/test-next-push.yml @@ -0,0 +1,33 @@ +name: test-next-push + +on: + push: + branches: [ next ] + workflow_dispatch: + +concurrency: prr:pre-release + +jobs: + test: + uses: ./.github/workflows/test.yml + + publish-prerelease: + needs: test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 20 + - run: npm ci + - run: npm run build + - run: npx pr-release pr --verbose --target master --source next --compact --verbose --minimize-semver-change + env: + GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} + # The following will publish a prerelease to npm + - run: echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > ~/.npmrc + name: Setup NPM Auth + env: + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + - run: npx pr-release infer-prerelease --preid=next --target master --source next --verbose --publish --minimize-semver-change + name: Publish diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 000000000..69bc69bb9 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,47 @@ +name: test + +on: + pull_request: + branches: [ next ] + workflow_dispatch: + workflow_call: + +permissions: + actions: write + contents: read + +# This uses actions/checkout instead of `git clone` directly since it's way +# easier than parsing everything out. + +jobs: + lint-docs: + uses: ./.github/workflows/_npm-task.yml + with: + task: lint:docs + continue-on-error: true + + lint-js: + uses: ./.github/workflows/_npm-task.yml + with: + task: lint:js + + build-js: + needs: lint-js + uses: ./.github/workflows/_npm-task.yml + with: + task: build + + test-js: + needs: build-js + strategy: + matrix: + # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ + node-version: + - 16 + - 18 + - 20 + - 22 + uses: ./.github/workflows/_npm-task.yml + with: + node-version: ${{ matrix.node-version }} + task: test:js diff --git a/.gitignore b/.gitignore index b1bb6c4b6..b6539ad4f 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,6 @@ /.vscode /.DS_Store /.eslintcache -/.lint-docs-cache # These are artifacts from various scripts /dist diff --git a/README.md b/README.md index 0f452c176..912a8d4e1 100644 --- a/README.md +++ b/README.md @@ -3,11 +3,11 @@ [![npm Version](https://img.shields.io/npm/v/mithril.svg)](https://www.npmjs.com/package/mithril)   [![License](https://img.shields.io/npm/l/mithril.svg)](https://github.com/MithrilJS/mithril.js/blob/next/LICENSE)   [![npm Downloads](https://img.shields.io/npm/dm/mithril.svg)](https://www.npmjs.com/package/mithril)   -[![Build Status](https://img.shields.io/travis/MithrilJS/mithril.js/next.svg?colorB=brightgreen)](https://www.npmjs.com/package/mithril)   +[![Build Status](https://img.shields.io/github/actions/workflow/status/MithrilJS/mithril.js/.github%2Fworkflows%2Ftest-next-push.yml)](https://www.npmjs.com/package/mithril)   [![Donate at OpenCollective](https://img.shields.io/opencollective/all/mithriljs.svg?colorB=brightgreen)](https://opencollective.com/mithriljs)   [![Zulip, join chat](https://img.shields.io/badge/zulip-join_chat-brightgreen.svg)](https://mithril.zulipchat.com/) -- [What is Mithril.js?](#what-is-mithriljs?) +- [What is Mithril.js?](#what-is-mithriljs) - [Installation](#installation) - [Documentation](#documentation) - [Getting Help](#getting-help) diff --git a/docs/changelog.md b/docs/changelog.md index 790de1804..5ef7f899c 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -46,6 +46,7 @@ PSA: changes to [`mithril/stream`](stream.md) are now specified in this changelo - Add `URLSearchParams` support to `m.request` ([#2695](https://github.com/MithrilJS/mithril.js/pull/2695) [@Coteh](https://github.com/Coteh)) - Standardise vnode text representation ([#2670](https://github.com/MithrilJS/mithril.js/pull/2670)) [@barneycarroll](https://github.com/barneycarroll) - API: Invalid escapes in routes are now safely handled. [@StephanHoyer](https://github.com/StephanHoyer) based on older [fix](https://github.com/MithrilJS/mithril.js/pull/2061) by [@dead-claudia](https://github.com/dead-claudia) +- Use window and document from render target instead of using globals. ([#2897](https://github.com/MithrilJS/mithril.js/pull/2897)) Important note: if you were using any of these undocumented tools, they are no longer available as of this release. This is not considered a breaking change as they were written for internal usage and as of v2 are all 100% unsupported in userland. diff --git a/docs/index.md b/docs/index.md index 3460a90d6..f96a96fa2 100644 --- a/docs/index.md +++ b/docs/index.md @@ -321,7 +321,7 @@ m.route(root, "/splash", { Basically, XHR is just a way to talk to a server. -Let's change our click counter to make it save data on a server. For the server, we'll use [REM](https://rem-rest-api.herokuapp.com), a mock REST API designed for toy apps like this tutorial. +Let's change our click counter to make it save data on a server. For the server, we'll use [REM](https://mithril-rem.fly.dev), a mock REST API designed for toy apps like this tutorial. First we create a function that calls `m.request`. The `url` specifies an endpoint that represents a resource, the `method` specifies the type of action we're taking (typically the `PUT` method [upserts](https://en.wiktionary.org/wiki/upsert)), `body` is the payload that we're sending to the endpoint and `withCredentials` means to enable cookies (a requirement for the REM API to work) @@ -330,7 +330,7 @@ var count = 0 var increment = function() { m.request({ method: "PUT", - url: "//rem-rest-api.herokuapp.com/api/tutorial/1", + url: "//mithril-rem.fly.dev/api/tutorial/1", body: {count: count + 1}, withCredentials: true, }) @@ -366,7 +366,7 @@ var count = 0 var increment = function() { m.request({ method: "PUT", - url: "//rem-rest-api.herokuapp.com/api/tutorial/1", + url: "//mithril-rem.fly.dev/api/tutorial/1", body: {count: count + 1}, withCredentials: true, }) diff --git a/docs/installation.md b/docs/installation.md index 07ac4db89..13c1e4fb4 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -127,7 +127,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](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/). +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/). 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. @@ -206,7 +206,7 @@ If you open bin/app.js, you'll notice that the Webpack bundle is not minified, s "name": "my-project", "scripts": { "start": "webpack src/index.js --output bin/app.js -d --watch", - "build": "webpack src/index.js --output bin/app.js -p", + "build": "webpack src/index.js --output bin/app.js -p" } } ``` diff --git a/docs/nav-methods.md b/docs/nav-methods.md index 6d15f06eb..1384730d9 100644 --- a/docs/nav-methods.md +++ b/docs/nav-methods.md @@ -11,6 +11,7 @@ - [m.trust](trust.md) - [m.fragment](fragment.md) - [m.redraw](redraw.md) + - [m.censor](censor.md) - Optional - [Stream](stream.md) - Tooling diff --git a/docs/simple-application.md b/docs/simple-application.md index 1736e1b2c..38f8aeada 100644 --- a/docs/simple-application.md +++ b/docs/simple-application.md @@ -6,7 +6,7 @@ A complete walkthrough tutorial for building your first simple application in Mi Let's develop a simple application that shows off how to do most of the major things you would need to deal with while using Mithril. -*An interactive example of the end result can be seen [here](https://flems.io/#0=N4IgzgpgNhDGAuEAmIBcICqkBOBZA9ktAHQBWYIANCAGYCWMFqA2qAHYCGAthGpjgSJQyFarHxtEkvgDcO2AARYIigLwLgAHTYLdCqHTDxUC5gF1K2vfvwckAGUPGFNAK5sEdCQAoAlBqtrPWwIeFdsHS5iEIBHVwgjby0dINSeeAALQhNNEABxAFEAFVzLFNTrcKgckAz4eAAHMFQAehaQrgBaEKNOjga6YgyVfABrV36G4nEuFv66FtccMFLAir0AdzpMgGEQokk6DihmhXhseLL1gF9fNaDiTIg2bzcPeC8XntcoeH9k9bWZTYYgGIwKdTfX7EJAceAce7WW73a5le6wcIhSQmYCo+5QWxIExvTw+OhIf6I4KhcKRaIQOIJeBJKlpUJZIkKXKFEpUVlBKo1OqNZptDrdJl9AZDEbjSbTfCzeaLZYtXIKADUCnJV0Bui2u32zw+x1O50u-OR5QeTxeJI+PihfwC1vWwOmmONEIUTstd2teLY9zAHBkEGJ7lJL0prupYQiCiisXiiQBesT7OyXJAAAUMLzdXrBdnhU1Wu0IF0evApYNhtgxhMGlMZnMBiqVGA1SBNUocB7sFj4MQdfzrAAjQgATxM7oxg+NhcBBoye2QxqOJxM5ogS6R-qR2mu2io4GgcAdbCYIAAjKgbwBmECo9jcXjoYGOIwiU-iSTG2R5D7FQv3gb0010CQ6DYbZZ37Ak7FApcZDoCANgjd5Pj8F11hCeNIm8XJiCWFROjBeBSmAkFyOILh+leSNL28EjsBjdMfRpBMuG8JN8FcRBiEcNhRkoDQMhCGgahaZBtm7XsWJHJBRNgKAODAU4AHIWLIpxOm2SsNNRBQFPobAjAAOTfXt1XVLUFNUiy3wPCpbmc3RjzYDzn0oV8eD4YEADF8GwKJyF-CQpHgQDFEC4KuHA+4oJg5x7SwmQ2EICB-ndBCkG8dLMuIOFzjARTfEDawULQjCo2wiCgjw2lE0I2g4so+r2IkMBXHHLhYJcRisKynD2IqCBiAaEIw0kAARCAaA4H5mTc0agX7EMwz8McXO29zROYXbmtyVTxxIE7oEo3IAroMywM4Hhcl8PcKm43JoIafiRzYD74GYeApwaCBVEQAAPeAzGYBpVNgCAsigIhsFUa7boUe6IDMdrDusJKfpqpjhuAOdPUkYhTMcnhvXG+FsAAc1CYg5CgeIKtWhRGfiOCVAHIdSZu8mIEO25nrSFrzuEMXLpAew1Lut9HuFoJXpAd7PpV36oY4GG4YR1RpfBNGMaoEbVpx-i8aG7L+3nHmHPgSyKfUKn5Dp4d2YgFnVrdzmQWt41QRl+2BdjVIhcOpXx34+AJGICP6gkP6AaB7reu2Q3RNyABlUMBZAJ7+TMFaPK8l8QDRvhpanPjhzCsQIoA9A5EUCuq4S60qvQgbMJ8AqiDYipGq4lq6Og-3K-4yiDuDxWWs4GRaOeVwJ6xvRuN4-jxqEkTjdZ8T5pMDSWnIjTl727NgRWXPDoLhXrCVyAo0onvxtgDIGCQLEVusAuUSPE8S7L9A8oa4gD-JFPga8BKTXmnQEG3oNIAGJj5sAgRAbwSB8AYh4CTScSApzpxAIfJwmNrS5EIUYXIOJ+RYgRubHwfc9QDwIs3fioluKficL4T+egPJIiXKQmS8AWioHJBQ7e1hqEqFoS8J+9DASMOasw+ArDvCxRCqJJ+RV6hmU4ZaFEZQrTeV8u+EA0x1LhX-NIdAOC8EKC+j9USMdI4SBGjQCKJgMohWOAoG8AA2BosCABqKhYScAANyBDorTaCJgABMAAGfx4TPLaG0KPFuaZIk02id4hJsDFpRySboOiINOhbCQJkEwN44nVMSb-IMbB55sFcCNTJ2S4kKHaQ+XJSSPKpO0uREa5FOhGCnDAdxEgICFMTM7NpHScm1JSA0OwSBoI0xMHEnpKSGn9N0vpeKaZxya1GDTBs7hOTwIWpcjgUzJzYBod4-xCgwD4AMEgBQ8CkCfKmeIAk2ATDwIfICqZKywAaxnAoccBJYCjCma0tg6y5k3gWboJZnzVkmAAByPJvAAVmRWcCAYNOhEHENgOEnxxlsEmXUvpOAdK9D2agLIYZFBplBjWElwVyUSBMGclQBgqWbPqf7U6UARogrBSYSFGCYURJmfCuZ7S8UgyFaktWI1bn3KRbA55rz3mfKQDc4KCNuh2DoEsEwD58WThKWAOgAAvdFELjWkRtcCwwkqIVQtlSkOFCL2lVPxailZbA1nzNgbi-FZSKk5LiQAUlVQ02OUcdAHKOScvibBzkQBzUau5kiHk6peeSfVXzAiatImSlZFqFBWpVYEH5wV-mAofO60FqlwXQQFRATo0roWwvlf68NUzg1OsDRG5VUz2XErgFyy8lLqXJOFcmnlzKVAavTacrN-yIAYt3buoVz4LAgAFaMJgrBS5vnAdscSDBTxVD4KWUUixvrHIVLMPqmRsAMAAAIxOIHE4gAAWFon7b3CD6g04B-1AZ8DALAb9DQorXDMNcIAA)* +*An interactive example of the end result can be seen [here](https://flems.io/#0=N4IgzgpgNhDGAuEAmIBcICqkBOBZA9ktAHQBWYIANCAGYCWMFqA2qAHYCGAthGpjgSJQyFarHxtEkvgDcO2AARYIigLwLgAHTYLdCqHTDxUC5gF1K2vfvwckAGUPGFNAK5sEdCQAoAlBqtrPWwIeFdsHS5iEIBHVwgjby0dINSeeAALQhNNEABxAFEAFVzLFNTrcKgckAz4eAAHMFQAehauOkzsBgBaEKiaKABPYiIZFo4GuhbXHDBSwIq9AHdOjIBhEKJJOg4oZoV4bHiypYBfX0Wg4kyINm83D3gve5CwVyh4f2Sl62VsYgGIwKdRvD7wUYceAcK7WC5XM5lK6wcIhSQmYCIq5QWxIEyPTw+OhIb6w4KhcKRaIQOIJeBJMlpUJZPEKXKFEpURlBKo1OqNZptDpdXr9YiDEZjCZTGZzFq5BQAagUxNOv10q0ym2Qd2eewORxO3Ph5Wut3uBOePjBn1JpqW-2IKOwaPgIIUNvgxsupqxbCuYA4Mgg+PchPudqWITCEQUUVi8USP3VceZ2TZIAAChhOWr1byM-ymq12mtulA+hABsNRhBxpNprMVGB5SAlUocE7UbriKrudYAEaEIYmR3O11536ajZbXW7fYmQ0QSdwn1w7RnbRUcDQOBWthMEAAVlQABYj5QAIwAdjPF4ATAAOO8gRHsbi8dD-RxGETb8SSLqsjyB2Kg-m66jJroEh0GwnSjp2OJ2OBk4yHQEDLKGTwvH4AT2uSMaRN4uTEE22A9ECXpUKBAKUcQXCTA8Yb7t4ZGRim0aUnG3jxvgriIMQjhsAA1pQGgZCENA1C0yCdK27Zkb2SBibAUAcGABwAORkRRTg9J0VaaYiCiKfQ2BGAAch+7YKgqyqKWplkfmuFQXC5uibmwnmvpQ748Hw-wAGL4NgUTkP+EhSPAwGKEFIVcO6UEKDBcHOJaOEyGwhAQN8jpIUg3iZdlxBQkcYBKb4frWGhGFYeGuFJdYnGxlwxG0PFpR4SmQQSO8A7CnVLE5V13UVBAxANCEwaSAAIhANAcOCfj9imjqBsGy34eqnndcZzArborW5GpA4kCd0CdbkgV0OZbqcDwuS+CuFRHSAsENPxvZsB98DMPAQwNBAqiIAAHvAZjMA0amwBAWRQEQ2CqNdt0KPdEBmJ1jUpilP2DThw3AGO3aSOKN1OTw7rjdC2AAOahMQchQPEVWjbojPxAhKhdi6PZmeTEAHQoFzPWkbXncI4uXSA9jqXdH6PSLQSve9n0q79UMcDDcMI6oMvAmjGPUVj6o4-xeM+ATRM8yTjnwFZFPqFT8h0xC7MQCzrNu5zALjj2tv2wLW1BMLguvQO-HwBIxDh-UEh-QDQN9cKhtibkADKQYCyAT3cmY7lCxuW5viAaN8DLQx8RC4ViJFQHoHIijl5XiVXDVmEuMxGVZUQ7GpM1RG5AxsGAhwFf8Z1+1B9Yr2cDI9F3K4E+C9PPHRJX41CaJI2s7oEnzSYmktJRmnL3oxm5P88zZ4LeeKyvuSQOGnVFUQToZAwSBovn1h5wihdsD5Pyn4QCTAaH+GugFpDoF4vxcak15p0BBu6TSABiE+bAYGIG8EgfAKIeAkyHEgIYqcQBHycJjK4uQyFGFyBibkaIEbmwjNvX4-duJN34mJVq34nC+G-mfBEk4qGyXgC0VAxJaEsKancRhHdsI+BfgTQWbDWocPgFw7wcVQpiUUSVeo5k+HGkERuH0gCS4fj4E6DSEVIHRXQIQ4hCgvo-TEtHCOEgRo0EiiYLKoU9gKEvAANgaEggAaioJAHBOAAG5AgMVprBEw94AAMITYleW0NoEeY83TJniTTRJATUlIMWpHdJh0OAgx6KsJAmQTCXmSY0tJ-8sn4NcCNfJhTkkKG6QAZmKekzyWSdKURGpRHoRghgwB8RICA5S4zOy6T0opzSUgNDsEgWCNMTDJMGZktgpEcC6SMPpRACVkwDk1sJGm2A+JsFZCghaTyODzKHNgWRl4QkKDAPgAwSAFAoKQEC+Z4gcTYBMCg3pUL5mbLABrEcCgBw4lgMJeZnS2A7OWZ8kG8z1lAq2SYR8XzLxHlWboUG8AehEHENgKELwZlsDmS0g5Iy9IGS4KgLIwZFDJgpVSuAIU6USBMO4BGBhGV7P9Ac8WI1YXwpMEi3BqK4mLIxcs7ppKcXMucfxEabyPlfJ+X8gFQKkCvJCgjPodg6CzBML0sliL8BVLAHQAAXgSx17yVA9CHFqlIcq1IIsVSitFqrMXdIaQ6vFmy2DbJWUgklDqal1KKckgApJKrJMdI46AuVcm5dyHkQGLear14KAmGt+cSE1wLAj6u9bSzZtqFD2r9boUFIUIVQt6TCww8qVRsHFRAH1yLlUpHReG+NuKNkesjQmzV8y+XUsFfuBlTKMlSrcbHDFXKVB6vzbc0VEKICPhPSeyVr4LAgHFcJJgrBzH+WgWWBg24qh8CLIKGY31rlOnwFwUsIooAAAF7zEGScQU8AGJIMHosPauIB-qAz4GAWA3QGjRTOGYM4QA)* First let's create an entry point for the application. Create a file `index.html`: @@ -80,7 +80,7 @@ var User = { module.exports = User ``` -Then we can add an `m.request` call to make an XHR request. For this tutorial, we'll make XHR calls to the REM (DEAD LINK, FIXME: https //rem-rest-api.herokuapp.com/) API, a mock REST API designed for rapid prototyping. This API returns a list of users from the `GET https://rem-rest-api.herokuapp.com/api/users` endpoint. Let's use `m.request` to make an XHR request and populate our data with the response of that endpoint. +Then we can add an `m.request` call to make an XHR request. For this tutorial, we'll make XHR calls to the REM (DEAD LINK, FIXME: https //rem-rest-api.herokuapp.com/) API, a mock REST API designed for rapid prototyping. This API returns a list of users from the `GET https://mithril-rem.fly.dev/api/users` endpoint. Let's use `m.request` to make an XHR request and populate our data with the response of that endpoint. *Note: third-party cookies may have to be enabled for the REM endpoint to work.* @@ -93,7 +93,7 @@ var User = { loadList: function() { return m.request({ method: "GET", - url: "https://rem-rest-api.herokuapp.com/api/users", + url: "https://mithril-rem.fly.dev/api/users", withCredentials: true, }) .then(function(result) { @@ -422,7 +422,7 @@ var User = { loadList: function() { return m.request({ method: "GET", - url: "https://rem-rest-api.herokuapp.com/api/users", + url: "https://mithril-rem.fly.dev/api/users", withCredentials: true, }) .then(function(result) { @@ -445,7 +445,7 @@ var User = { loadList: function() { return m.request({ method: "GET", - url: "https://rem-rest-api.herokuapp.com/api/users", + url: "https://mithril-rem.fly.dev/api/users", withCredentials: true, }) .then(function(result) { @@ -457,7 +457,7 @@ var User = { load: function(id) { return m.request({ method: "GET", - url: "https://rem-rest-api.herokuapp.com/api/users/" + id, + url: "https://mithril-rem.fly.dev/api/users/" + id, withCredentials: true, }) .then(function(result) { @@ -563,7 +563,7 @@ var User = { loadList: function() { return m.request({ method: "GET", - url: "https://rem-rest-api.herokuapp.com/api/users", + url: "https://mithril-rem.fly.dev/api/users", withCredentials: true, }) .then(function(result) { @@ -575,7 +575,7 @@ var User = { load: function(id) { return m.request({ method: "GET", - url: "https://rem-rest-api.herokuapp.com/api/users/" + id, + url: "https://mithril-rem.fly.dev/api/users/" + id, withCredentials: true, }) .then(function(result) { @@ -586,7 +586,7 @@ var User = { save: function() { return m.request({ method: "PUT", - url: "https://rem-rest-api.herokuapp.com/api/users/" + User.current.id, + url: "https://mithril-rem.fly.dev/api/users/" + User.current.id, body: User.current, withCredentials: true, }) diff --git a/docs/stream.md b/docs/stream.md index da1eac403..8e39af84b 100644 --- a/docs/stream.md +++ b/docs/stream.md @@ -462,7 +462,7 @@ Pending streams can be created by calling `stream()` with no parameters. var pending = stream() ``` -If a stream is dependent on more than one stream, any of its parent streams is in a pending state, the dependent streams is also in a pending state, and does not update its value. +If a stream is dependent on more than one stream and any of its parent streams is in a pending state, the dependent stream is also in a pending state, and does not update its value. ```javascript var a = stream(5) @@ -558,13 +558,13 @@ console.log(serialized) // logs 123 Unlike libraries like Knockout, Mithril.js streams do not trigger re-rendering of templates. Redrawing happens in response to event handlers defined in Mithril.js component views, route changes, or after [`m.request`](request.md) calls resolve. -If redrawing is desired in response to other asynchronous events (e.g. `setTimeout`/`setInterval`, websocket subscription, 3rd party library event handler, etc), you should manually call [`m.redraw()`](redraw.md) +If redrawing is desired in response to other asynchronous events (e.g. `setTimeout`/`setInterval`, websocket subscription, 3rd party library event handler, etc.), you should manually call [`m.redraw()`](redraw.md). --- ### What is Fantasy Land -[Fantasy Land](https://github.com/fantasyland/fantasy-land) specifies interoperability of common algebraic structures. In plain english, that means that libraries that conform to Fantasy Land specs can be used to write generic functional style code that works regardless of how these libraries implement the constructs. +[Fantasy Land](https://github.com/fantasyland/fantasy-land) specifies interoperability of common algebraic structures. In plain English, that means that libraries that conform to Fantasy Land specs can be used to write generic functional style code that works regardless of how these libraries implement the constructs. For example, say we want to create a generic function called `plusOne`. The naive implementation would look like this: @@ -574,7 +574,7 @@ function plusOne(a) { } ``` -The problem with this implementation is that it can only be used with a number. However it's possible that whatever logic produces a value for `a` could also produce an error state (wrapped in a Maybe or an Either from a library like [Sanctuary](https://github.com/sanctuary-js/sanctuary) or [Ramda-Fantasy](https://github.com/ramda/ramda-fantasy)), or it could be a Mithril.js stream, or a [flyd](https://github.com/paldepind/flyd) stream, etc. Ideally, we wouldn't want to write a similar version of the same function for every possible type that `a` could have and we wouldn't want to be writing wrapping/unwrapping/error handling code repeatedly. +The problem with this implementation is that it can only be used with a number. However it's possible that whatever logic produces a value for `a` could also produce an error state (wrapped in a Maybe or an Either from a library like [Sanctuary](https://github.com/sanctuary-js/sanctuary) or [Ramda-Fantasy](https://github.com/ramda/ramda-fantasy)), or it could be a Mithril.js stream, a [Flyd](https://github.com/paldepind/flyd) stream, etc. Ideally, we wouldn't want to write a similar version of the same function for every possible type that `a` could have and we wouldn't want to be writing wrapping/unwrapping/error handling code repeatedly. This is where Fantasy Land can help. Let's rewrite that function in terms of a Fantasy Land algebra: diff --git a/docs/vnodes.md b/docs/vnodes.md index a9313f257..146932718 100644 --- a/docs/vnodes.md +++ b/docs/vnodes.md @@ -112,11 +112,11 @@ When creating libraries that emit vnodes, you should use this module instead of ### Avoid anti-patterns -#### Avoid memoizing mutable vnodes +#### Avoid reusing vnodes -Vnodes are supposed to represent the state of the DOM at a certain point in time. Mithril.js' rendering engine assumes a reused vnode is unchanged, so modifying a vnode that was used in a previous render will result in undefined behavior. +Vnodes are supposed to represent the state of the DOM at a certain point in time. Mithril.js's rendering engine assumes a reused vnode is unchanged, so modifying a vnode that was used in a previous render will result in undefined behavior. -It is possible to reuse vnodes to prevent a diff, but it's preferable to use the `onbeforeupdate` hook to make your intent clear to other developers (or your future self). +It is possible to reuse vnodes in place to prevent a diff, but it's preferable to use the [`onbeforeupdate`](lifecycle-methods.md#onbeforeupdate). #### Avoid passing model data directly to components via attributes @@ -174,4 +174,4 @@ var BetterListComponent = { })) } } -``` \ No newline at end of file +``` diff --git a/examples/editor/index.html b/examples/editor/index.html index 32e2da0b7..dea4874f1 100644 --- a/examples/editor/index.html +++ b/examples/editor/index.html @@ -12,7 +12,7 @@
- +