diff --git a/.eslintrc b/.eslintrc index 6cdfd8fe5..21f5e1634 100644 --- a/.eslintrc +++ b/.eslintrc @@ -8,12 +8,22 @@ "no-mixed-spaces-and-tabs": 2, "quotes": [2, "single", "avoid-escape"], "semi": 2, - "space-after-keywords": 2, + "keyword-spacing": 2, "space-before-function-paren": 2, "curly": 0, "consistent-return": 0, "no-use-before-define": 0, + "no-process-exit": 0, "strict": 0 - } + }, + "overrides": [ + { + "files": ["mustache.js"], + "parserOptions": { + "sourceType": "module", + "ecmaVersion": 2015 + } + } + ] } \ No newline at end of file diff --git a/.esmrc b/.esmrc new file mode 100644 index 000000000..c40474328 --- /dev/null +++ b/.esmrc @@ -0,0 +1,8 @@ +{ + cjs: { + // Ensure ESM `export default` ends up as the root, e.g. `module.exports` when + // being `require()`d from CJS code. This is not spec compliant, but that does + // not matter because only use this `esm` package trickery locally while testing + dedefault: true + } +} diff --git a/.github/workflows/usage.yml b/.github/workflows/usage.yml new file mode 100644 index 000000000..c4c493313 --- /dev/null +++ b/.github/workflows/usage.yml @@ -0,0 +1,140 @@ +name: Package usage + +on: [push, pull_request] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js + uses: actions/setup-node@v1 + with: + node-version: 14.x + - name: npm install and build + run: | + npm install + npm run build + - name: Store build-output for later + uses: actions/upload-artifact@v2 + with: + name: build-output + path: | + mustache.js + mustache.mjs + + package: + runs-on: ubuntu-latest + + needs: build + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js + uses: actions/setup-node@v1 + with: + node-version: 14.x + - name: Get build-output from build step + uses: actions/download-artifact@v2 + with: + name: build-output + - name: Create package tarball + run: | + export ARCHIVE_FILENAME=$(npm pack | tail -n 1) + mv $ARCHIVE_FILENAME mustache.tgz + - name: Store package tarball for later + uses: actions/upload-artifact@v2 + with: + name: package-output + path: mustache.tgz + + common-js-usage: + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [10.x, 12.x, 14.x, 15.x] + + needs: package + steps: + - uses: actions/checkout@v1 + - name: Setup Node.js + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - name: Get package tarball from package step + uses: actions/download-artifact@v2 + with: + name: package-output + - name: Package, install and test + run: | + export UNPACK_DESTINATION=$(mktemp -d) + mv mustache.tgz $UNPACK_DESTINATION + cp test/module-systems/commonjs-test.js $UNPACK_DESTINATION + cd $UNPACK_DESTINATION + npm install mustache.tgz + node commonjs-test.js + + esm-usage: + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [14.x, 15.x] + + needs: package + steps: + - uses: actions/checkout@v1 + - name: Setup Node.js + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - name: Get package tarball from package step + uses: actions/download-artifact@v2 + with: + name: package-output + - name: Package, install and test + run: | + export UNPACK_DESTINATION=$(mktemp -d) + mv mustache.tgz $UNPACK_DESTINATION + cp test/module-systems/esm-test.mjs $UNPACK_DESTINATION + cp test/module-systems/esm-test-exports.mjs $UNPACK_DESTINATION + cd $UNPACK_DESTINATION + npm install mustache.tgz + node esm-test.mjs + node esm-test-exports.mjs + + browser-usage: + runs-on: ubuntu-latest + + needs: build + steps: + - uses: actions/checkout@v1 + - name: Setup Node.js + uses: actions/setup-node@v1 + with: + node-version: 12.x + - name: Get build-output from build step + uses: actions/download-artifact@v2 + with: + name: build-output + - name: Install and test + run: | + npm ci + npx mocha test/module-systems/browser-test.js + + deno-usage: + runs-on: ubuntu-latest + + needs: build + steps: + - uses: actions/checkout@v1 + - uses: denolib/setup-deno@master + with: + deno-version: 'v1.0.0' + - name: Get build-output from build step + uses: actions/download-artifact@v2 + with: + name: build-output + - run: deno --version + - run: deno test --allow-net=deno.land test/module-systems/deno-test.ts diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml new file mode 100644 index 000000000..0a86a51db --- /dev/null +++ b/.github/workflows/verify.yml @@ -0,0 +1,82 @@ +name: Verify changes + +on: [push, pull_request] + +jobs: + lint: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js + uses: actions/setup-node@v1 + with: + node-version: 14.x + - run: npm install + - run: npm run test-lint + + tests: + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [10.x, 12.x, 14.x, 15.x] + + steps: + - uses: actions/checkout@v2 + with: + submodules: recursive + - name: Setup Node.js + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - name: npm install and test + run: | + npm install + npm run test-unit + + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js + uses: actions/setup-node@v1 + with: + node-version: 14.x + - name: npm install and build + run: | + npm install + npm run build + - name: Store build-output for later + uses: actions/upload-artifact@v2 + with: + name: build-output + path: | + mustache.js + mustache.mjs + + tests-on-legacy: + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [0.10.x, 0.12.x, 4.x, 6.x, 8.x] + + needs: build + steps: + - uses: actions/checkout@v2 + with: + submodules: recursive + - name: Setup Node.js + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - name: Get build-output from build step + uses: actions/download-artifact@v2 + with: + name: build-output + - name: npm install and test + run: | + npm install mocha@3 chai@3 + npm run test-unit diff --git a/.gitignore b/.gitignore index 6ad717ee4..adaaa819c 100644 --- a/.gitignore +++ b/.gitignore @@ -6,5 +6,8 @@ yui3 qooxdoo.mustache.js test/render-test-browser.js npm-debug.log - -test/render-test-browser.js \ No newline at end of file +.DS_Store +test/render-test-browser.js +.idea/ +mustache.mjs +mustache.min.js diff --git a/.travis.yml b/.travis.yml index f86ffe2ef..a81a06dcd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,13 +1,9 @@ language: node_js node_js: - - 0.8 - - '0.10' - - 0.12 -before_install: - - npm install -g npm + - 8 script: - - npm test - - "test $TRAVIS_PULL_REQUEST != 'false' || test $TRAVIS_NODE_VERSION != '0.12' || npm run test-browser" + - npm run build + - "test $TRAVIS_PULL_REQUEST != 'false' || test $TRAVIS_NODE_VERSION != '8' || npm run test-browser" env: global: - secure: L0dg0jr2fwkc2tPwP5svybILPBn2qdLzMrWc5tEXg3MPcy8D59Gvf+ri7INqo+ETPM20o5CsaDCH+LHUNS/V0G4VG1ajvsy7d8uh3hnb/K6VfVui/CjsHIqOcOZrbxVxgyX+iMXEXAj0+Syow9uDQHVhrz1qqad1n79likNCXa4= diff --git a/.zuul.yml b/.zuul.yml index b5703b1bf..2bf6e0e59 100644 --- a/.zuul.yml +++ b/.zuul.yml @@ -5,4 +5,8 @@ browsers: - name: firefox version: latest - name: ie - version: 8..latest \ No newline at end of file + version: 11..latest +concurrency: 1 +tunnel: + type: ngrok + bind_tls: false diff --git a/CHANGELOG.md b/CHANGELOG.md index 39dcb74a5..9f6f89e78 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,354 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +## [4.2.0] / 28 March 2021 + +### Added + +* [#773]: Add package.json `exports` field, by [@manzt]. + +## [4.1.0] / 6 December 2020 + +### Added + +* [#764]: `render()` now recognizes a config object argument, by [@pineapplemachine]. + +### Fixed + +* [#764]: Ask custom `escape` functions to escape all types of values (including `number`s), by [@pineapplemachine]. + +## [4.0.1] / 15 March 2020 + +### Fixed + + * [#739]: Fix custom delimiters in nested partials, by [@aielo]. + +## [4.0.0] / 16 January 2020 + +Majority of using projects don't have to worry by this being a new major version. + +**TLDR;** if your project manipulates `Writer.prototype.parse | Writer.cache` directly or uses `.to_html()`, you probably have to change that code. + +This release allows the internal template cache to be customised, either by disabling it completely +or provide a custom strategy deciding how the cache should behave when mustache.js parses templates. + +```js +const mustache = require('mustache'); + +// disable caching +Mustache.templateCache = undefined; + +// or use a built-in Map in modern environments +Mustache.templateCache = new Map(); +``` + +Projects that wanted to customise the caching behaviour in earlier versions of mustache.js were forced to +override internal method responsible for parsing templates; `Writer.prototype.parse`. In short, that was unfortunate +because there is more than caching happening in that method. + +We've improved that now by introducing a first class API that only affects template caching. + +The default template cache behaves as before and is still compatible with older JavaScript environments. +For those who wants to provide a custom more sopisiticated caching strategy, one can do that with an object that adheres to the following requirements: + +```ts +{ + set(cacheKey: string, value: string): void + get(cacheKey: string): string | undefined + clear(): void +} +``` + +### Added + +* [#731]: Allow template caching to be customised, by [@AndrewLeedham]. + +### Removed + +* [#735]: Remove `.to_html()`, by [@phillipj]. + +## [3.2.1] / 30 December 2019 + +### Fixed + + * [#733]: Allow the CLI to use JavaScript views when the project has ES6 modules enabled, by [@eobrain]. + +## [3.2.0] / 18 December 2019 + +### Added + +* [#728]: Expose ECMAScript Module in addition to UMD (CommonJS, AMD & global scope), by [@phillipj] and [@zekth]. + +### Using mustache.js as an ES module + +To stay backwards compatible with already using projects, the default exposed module format is still UMD. +That means projects using mustache.js as an CommonJS, AMD or global scope module, from npm or directly from github.com +can keep on doing that for now. + +For those projects who would rather want to use mustache.js as an ES module, the `mustache/mustache.mjs` file has to +be `import`ed directly. + +Below are some usage scenarios for different runtimes. + +#### Modern browser with ES module support + +```html + + +``` + +#### [Node.js](https://nodejs.org) (>= v13.2.0 or using --experimental-modules flag) + +```js +// index.mjs +import mustache from 'mustache/mustache.mjs' + +console.log(mustache.render('Hello {{name}}!', { name: 'Santa' })) +// Hello Santa! +``` + +ES Module support for Node.js will be improved in the future when [Conditional Exports](https://nodejs.org/api/esm.html#esm_conditional_exports) +is enabled by default rather than being behind an experimental flag. + +More info in [Node.js ECMAScript Modules docs](https://nodejs.org/api/esm.html). + +#### [Deno](https://deno.land/) + +```js +// index.ts +import mustache from 'https://unpkg.com/mustache@3.2.0/mustache.mjs' + +console.log(mustache.render('Hello {{name}}!', { name: 'Santa' })) +// Hello Santa! +``` + +## [3.1.0] / 13 September 2019 + +### Added + + * [#717]: Added support .js files as views in command line tool, by [@JEStaubach]. + +### Fixed + + * [#716]: Bugfix for indentation of inline partials, by [@yotammadem]. + +## [3.0.3] / 27 August 2019 + +### Added + + * [#713]: Add test cases for custom functions in partials, by [@wol-soft]. + +### Fixed + + * [#714]: Bugfix for wrong function output in partials with indentation, by [@phillipj]. + +## [3.0.2] / 21 August 2019 + +### Fixed + + * [#705]: Fix indentation of partials, by [@kevindew] and [@yotammadem]. + +### Dev + + * [#701]: Fix test failure for Node 10 and above, by [@andersk]. + * [#704]: Lint all test files just like the source files, by [@phillipj]. + * Start experimenting & comparing GitHub Actions vs Travis CI, by [@phillipj]. + +## [3.0.1] / 11 November 2018 + + * [#679]: Fix partials not rendering tokens when using custom tags, by [@stackchain]. + +## [3.0.0] / 16 September 2018 + +We are very happy to announce a new major version of mustache.js. We want to be very careful not to break projects +out in the wild, and adhering to [Semantic Versioning](http://semver.org/) we have therefore cut this new major version. + +The changes introduced will likely not require any actions for most using projects. The things to look out for that +might cause unexpected rendering results are described in the migration guide below. + +A big shout out and thanks to [@raymond-lam] for this release! Without his contributions with code and issue triaging, +this release would never have happened. + +### Major + +* [#618]: Allow rendering properties of primitive types that are not objects, by [@raymond-lam]. +* [#643]: `Writer.prototype.parse` to cache by tags in addition to template string, by [@raymond-lam]. +* [#664]: Fix `Writer.prototype.parse` cache, by [@seminaoki]. + +### Minor + +* [#673]: Add `tags` parameter to `Mustache.render()`, by [@raymond-lam]. + +### Migrating from mustache.js v2.x to v3.x + +#### Rendering properties of primitive types + +We have ensured properties of primitive types can be rendered at all times. That means `Array.length`, `String.length` +and similar. A corner case where this could cause unexpected output follows: + +View: +``` +{ + stooges: [ + { name: "Moe" }, + { name: "Larry" }, + { name: "Curly" } + ] +} +``` + +Template: +``` +{{#stooges}} + {{name}}: {{name.length}} characters +{{/stooges}} +``` + +Output with v3.0: +``` + Moe: 3 characters + Larry: 5 characters + Curly: 5 characters +``` + +Output with v2.x: +``` + Moe: characters + Larry: characters + Curly: characters +``` + +#### Caching for templates with custom delimiters + +We have improved the templates cache to ensure custom delimiters are taken into consideration for the cache. +This improvement might cause unexpected rendering behaviour for using projects actively using the custom delimiters functionality. + +Previously it was possible to use `Mustache.parse()` as a means to set global custom delimiters. If custom +delimiters were provided as an argument, it would affect all following calls to `Mustache.render()`. +Consider the following: + +```js +const template = "[[item.title]] [[item.value]]"; +mustache.parse(template, ["[[", "]]"]); + +console.log( + mustache.render(template, { + item: { + title: "TEST", + value: 1 + } + }) +); + +>> TEST 1 +``` + +The above illustrates the fact that `Mustache.parse()` made mustache.js cache the template without considering +the custom delimiters provided. This is no longer true. + +We no longer encourage using `Mustache.parse()` for this purpose, but have rather added a fourth argument to +`Mustache.render()` letting you provide custom delimiters when rendering. + +If you still need the pre-parse the template and use custom delimiters at the same time, ensure to provide +the custom delimiters as argument to `Mustache.render()` as well. + +## [2.3.2] / 17 August 2018 + +This release is made to revert changes introduced in [2.3.1] that caused unexpected behaviour for several users. + +### Minor + + * [#670]: Rollback template cache causing unexpected behaviour, by [@raymond-lam]. + +## [2.3.1] / 7 August 2018 + +### Minor + + * [#643]: `Writer.prototype.parse` to cache by tags in addition to template string, by [@raymond-lam]. + * [#664]: Fix `Writer.prototype.parse` cache, by [@seminaoki]. + +### Dev + + * [#666]: Install release tools with npm rather than pre-commit hook & `Rakefile`, by [@phillipj]. + * [#667], [#668]: Stabilize browser test suite, by [@phillipj]. + +### Docs + + * [#644]: Document global Mustache.escape overriding capacity, by [@paultopia]. + * [#657]: Correct `Mustache.parse()` return type documentation, by [@bbrooks]. + +## [2.3.0] / 8 November 2016 + +### Minor + + * [#540]: Add optional `output` argument to mustache CLI, by [@wizawu]. + * [#597]: Add compatibility with amdclean, by [@mightyplow]. + +### Dev + + * [#553]: Assert `null` lookup when rendering an unescaped value, by [@dasilvacontin]. + * [#580], [#610]: Ignore eslint for greenkeeper updates, by [@phillipj]. + * [#560]: Fix CLI tests for Windows, by [@kookookchoozeus]. + * Run browser tests w/node v4, by [@phillipj]. + +### Docs + + * [#542]: Add API documentation to README, by [@tomekwi]. + * [#546]: Add missing syntax highlighting to README code blocks, by [@pra85]. + * [#569]: Update Ctemplate links in README, by [@mortonfox]. + * [#592]: Change "loadUser" to "loadUser()" in README, by [@Flaque]. + * [#593]: Adding doctype to HTML code example in README, by [@calvinf]. + +### Dependencies + + * eslint -> 2.2.0. Breaking changes fix by [@phillipj]. [#548] + * eslint -> 2.5.1. + * mocha -> 3.0.2. + * zuul -> 3.11.0. + +## [2.2.1] / 13 December 2015 + +### Fixes + + * Improve HTML escaping, by [@phillipj]. + * Fix inconsistency in defining global mustache object, by [@simast]. + * Fix switch-case indent error, by [@norfish]. + * Unpin chai and eslint versions, by [@dasilvacontin]. + * Update README.md with proper grammar, by [@EvanLovely]. + * Update mjackson username in README, by [@mjackson]. + * Remove syntax highlighting in README code sample, by [@imagentleman]. + * Fix typo in README, by [@Xcrucifier]. + * Fix link typo in README, by [@keirog]. + +## [2.2.0] / 15 October 2015 + +### Added + + * Add Partials support to CLI, by [@palkan]. + +### Changed + + * Move install instructions to README's top, by [@mateusortiz] + * Improved devhook install output, by [@ShashankaNataraj]. + * Clarifies and improves language in documentation, by [@jfmercer]. + * Linting CLI tool, by [@phillipj]. + * npm 2.x and node v4 on Travis, by [@phillipj]. + +### Fixes + + * Fix README spelling error to "aforementioned", by [@djchie]. + * Equal error message test in .render() for server and browser, by [@phillipj]. + +### Dependencies + + * chai -> 3.3.0 + * eslint -> 1.6.0 + ## [2.1.3] / 23 July 2015 ### Added @@ -135,6 +483,22 @@ This project adheres to [Semantic Versioning](http://semver.org/). * Fixed a bug that clashed with QUnit (thanks [@kannix]). * Added volo support (thanks [@guybedford]). +[4.2.0]: https://github.com/janl/mustache.js/compare/v4.1.0...v4.2.0 +[4.1.0]: https://github.com/janl/mustache.js/compare/v4.0.1...v4.1.0 +[4.0.1]: https://github.com/janl/mustache.js/compare/v4.0.0...v4.0.1 +[4.0.0]: https://github.com/janl/mustache.js/compare/v3.2.1...v4.0.0 +[3.2.1]: https://github.com/janl/mustache.js/compare/v3.2.0...v3.2.1 +[3.2.0]: https://github.com/janl/mustache.js/compare/v3.1.0...v3.2.0 +[3.1.0]: https://github.com/janl/mustache.js/compare/v3.0.3...v3.1.0 +[3.0.3]: https://github.com/janl/mustache.js/compare/v3.0.2...v3.0.3 +[3.0.2]: https://github.com/janl/mustache.js/compare/v3.0.1...v3.0.2 +[3.0.1]: https://github.com/janl/mustache.js/compare/v3.0.0...v3.0.1 +[3.0.0]: https://github.com/janl/mustache.js/compare/v2.3.2...v3.0.0 +[2.3.2]: https://github.com/janl/mustache.js/compare/v2.3.1...v2.3.2 +[2.3.1]: https://github.com/janl/mustache.js/compare/v2.3.0...v2.3.1 +[2.3.0]: https://github.com/janl/mustache.js/compare/v2.2.1...v2.3.0 +[2.2.1]: https://github.com/janl/mustache.js/compare/v2.2.0...v2.2.1 +[2.2.0]: https://github.com/janl/mustache.js/compare/v2.1.3...v2.2.0 [2.1.3]: https://github.com/janl/mustache.js/compare/v2.1.2...v2.1.3 [2.1.2]: https://github.com/janl/mustache.js/compare/v2.1.1...v2.1.2 [2.1.1]: https://github.com/janl/mustache.js/compare/v2.1.0...v2.1.1 @@ -162,23 +526,94 @@ This project adheres to [Semantic Versioning](http://semver.org/). [#270]: https://github.com/janl/mustache.js/issues/270 [#274]: https://github.com/janl/mustache.js/issues/274 [#466]: https://github.com/janl/mustache.js/issues/466 +[#540]: https://github.com/janl/mustache.js/issues/540 +[#542]: https://github.com/janl/mustache.js/issues/542 +[#546]: https://github.com/janl/mustache.js/issues/546 +[#548]: https://github.com/janl/mustache.js/issues/548 +[#553]: https://github.com/janl/mustache.js/issues/553 +[#560]: https://github.com/janl/mustache.js/issues/560 +[#569]: https://github.com/janl/mustache.js/issues/569 +[#580]: https://github.com/janl/mustache.js/issues/580 +[#592]: https://github.com/janl/mustache.js/issues/592 +[#593]: https://github.com/janl/mustache.js/issues/593 +[#597]: https://github.com/janl/mustache.js/issues/597 +[#610]: https://github.com/janl/mustache.js/issues/610 +[#643]: https://github.com/janl/mustache.js/issues/643 +[#644]: https://github.com/janl/mustache.js/issues/644 +[#657]: https://github.com/janl/mustache.js/issues/657 +[#664]: https://github.com/janl/mustache.js/issues/664 +[#666]: https://github.com/janl/mustache.js/issues/666 +[#667]: https://github.com/janl/mustache.js/issues/667 +[#668]: https://github.com/janl/mustache.js/issues/668 +[#670]: https://github.com/janl/mustache.js/issues/670 +[#618]: https://github.com/janl/mustache.js/issues/618 +[#673]: https://github.com/janl/mustache.js/issues/673 +[#679]: https://github.com/janl/mustache.js/issues/679 +[#701]: https://github.com/janl/mustache.js/issues/701 +[#704]: https://github.com/janl/mustache.js/issues/704 +[#705]: https://github.com/janl/mustache.js/issues/705 +[#713]: https://github.com/janl/mustache.js/issues/713 +[#714]: https://github.com/janl/mustache.js/issues/714 +[#716]: https://github.com/janl/mustache.js/issues/716 +[#717]: https://github.com/janl/mustache.js/issues/717 +[#728]: https://github.com/janl/mustache.js/issues/728 +[#733]: https://github.com/janl/mustache.js/issues/733 +[#731]: https://github.com/janl/mustache.js/issues/731 +[#735]: https://github.com/janl/mustache.js/issues/735 +[#739]: https://github.com/janl/mustache.js/issues/739 +[#764]: https://github.com/janl/mustache.js/issues/764 +[#773]: https://github.com/janl/mustache.js/issues/773 -[@Andersos]: https://github.com/Andersos -[@TiddoLangerak]: https://github.com/TiddoLangerak [@afc163]: https://github.com/afc163 +[@aielo]: https://github.com/aielo +[@andersk]: https://github.com/andersk +[@Andersos]: https://github.com/Andersos +[@AndrewLeedham]: https://github.com/AndrewLeedham +[@bbrooks]: https://github.com/bbrooks +[@calvinf]: https://github.com/calvinf [@cmbuckley]: https://github.com/cmbuckley [@cweider]: https://github.com/cweider [@dasilvacontin]: https://github.com/dasilvacontin +[@djchie]: https://github.com/djchie +[@eobrain]: https://github.com/eobrain +[@EvanLovely]: https://github.com/EvanLovely [@fallenice]: https://github.com/fallenice +[@Flaque]: https://github.com/Flaque [@guybedford]: https://github.com/guybedford +[@imagentleman]: https://github.com/imagentleman +[@JEStaubach]: https://github.com/JEStaubach [@jfmercer]: https://github.com/jfmercer [@jrburke]: https://github.com/jrburke [@kannix]: https://github.com/kannix +[@keirog]: https://github.com/keirog [@kkirsche]: https://github.com/kkirsche +[@kookookchoozeus]: https://github.com/kookookchoozeus [@kristijanmatic]: https://github.com/kristijanmatic +[@kevindew]: https://github.com/kevindew +[@manzt]: https://github.com/manzt +[@mateusortiz]: https://github.com/mateusortiz +[@mightyplow]: https://github.com/mightyplow [@mikesherov]: https://github.com/mikesherov [@mjackson]: https://github.com/mjackson +[@mortonfox]: https://github.com/mortonfox [@nagaozen]: https://github.com/nagaozen +[@norfish]: https://github.com/norfish +[@palkan]: https://github.com/palkan +[@paultopia]: https://github.com/paultopia [@pgilad]: https://github.com/pgilad [@phillipj]: https://github.com/phillipj +[@pineapplemachine]: https://github.com/pineapplemachine +[@pra85]: https://github.com/pra85 +[@raymond-lam]: https://github.com/raymond-lam +[@seminaoki]: https://github.com/seminaoki +[@ShashankaNataraj]: https://github.com/ShashankaNataraj +[@simast]: https://github.com/simast +[@stackchain]: https://github.com/stackchain +[@TiddoLangerak]: https://github.com/TiddoLangerak +[@tomekwi]: https://github.com/tomekwi +[@wizawu]: https://github.com/wizawu +[@wol-soft]: https://github.com/wol-soft +[@Xcrucifier]: https://github.com/Xcrucifier +[@yotammadem]: https://github.com/yotammadem [@yousefcisco]: https://github.com/yousefcisco +[@zekth]: https://github.com/zekth diff --git a/README.md b/README.md index 596b59b10..ea74fc830 100644 --- a/README.md +++ b/README.md @@ -2,101 +2,99 @@ > What could be more logical awesome than no logic at all? -[![Build Status](https://travis-ci.org/janl/mustache.js.svg?branch=master)](https://travis-ci.org/janl/mustache.js) [![Gitter chat](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/janl/mustache.js) +[![Build Status](https://travis-ci.org/janl/mustache.js.svg?branch=master)](https://travis-ci.org/janl/mustache.js) -[mustache.js](http://github.com/janl/mustache.js) is an implementation of the [mustache](http://mustache.github.com/) template system in JavaScript. +[mustache.js](http://github.com/janl/mustache.js) is a zero-dependency implementation of the [mustache](http://mustache.github.io/) template system in JavaScript. -[Mustache](http://mustache.github.com/) is a logic-less template syntax. It can be used for HTML, config files, source code - anything. It works by expanding tags in a template using values provided in a hash or object. +[Mustache](http://mustache.github.io/) is a logic-less template syntax. It can be used for HTML, config files, source code - anything. It works by expanding tags in a template using values provided in a hash or object. We call it "logic-less" because there are no if statements, else clauses, or for loops. Instead there are only tags. Some tags are replaced with a value, some nothing, and others a series of values. -For a language-agnostic overview of mustache's template syntax, see the `mustache(5)` [manpage](http://mustache.github.com/mustache.5.html). +For a language-agnostic overview of mustache's template syntax, see the `mustache(5)` [manpage](http://mustache.github.io/mustache.5.html). ## Where to use mustache.js? -You can use mustache.js to render mustache templates anywhere you can use JavaScript. This includes web browsers, server-side environments such as [node](http://nodejs.org/), and [CouchDB](http://couchdb.apache.org/) views. +You can use mustache.js to render mustache templates anywhere you can use JavaScript. This includes web browsers, server-side environments such as [Node.js](http://nodejs.org/), and [CouchDB](http://couchdb.apache.org/) views. -mustache.js ships with support for both the [CommonJS](http://www.commonjs.org/) module API and the [Asynchronous Module Definition](https://github.com/amdjs/amdjs-api/wiki/AMD) API, or AMD. +mustache.js ships with support for the [CommonJS](http://www.commonjs.org/) module API, the [Asynchronous Module Definition](https://github.com/amdjs/amdjs-api/wiki/AMD) API (AMD) and [ECMAScript modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules). + +In addition to being a package to be used programmatically, you can use it as a [command line tool](#command-line-tool). And this will be your templates after you use Mustache: !['stache](https://cloud.githubusercontent.com/assets/288977/8779228/a3cf700e-2f02-11e5-869a-300312fb7a00.gif) -## Who uses mustache.js? - -An updated list of mustache.js users is kept [on the Github wiki](http://wiki.github.com/janl/mustache.js/beard-competition). Add yourself or your company if you use mustache.js! - -## Contributing - -mustache.js is a mature project, but it continues to actively invite maintainers. You can help out a high-profile project that is used in a lot of places on the web. There is [plenty](https://github.com/janl/mustache.js/issues) of [work](https://github.com/janl/mustache.js/pulls) to do. No big commitment required, if all you do is review a single [Pull Request](https://github.com/janl/mustache.js/pulls), you are a maintainer. And a hero. - -### Your First Contribution +## Install -- review a [Pull Request](https://github.com/janl/mustache.js/pulls) -- fix an [Issue](https://github.com/janl/mustache.js/issues) -- update the [documentation](https://github.com/janl/mustache.js#usage) -- make a website -- write a tutorial +You can get Mustache via [npm](http://npmjs.com). -* * * +```bash +$ npm install mustache --save +``` ## Usage -Below is quick example how to use mustache.js: +Below is a quick example how to use mustache.js: ```js -var view = { +const Mustache = require('mustache'); + +const view = { title: "Joe", - calc: function () { - return 2 + 4; - } + calc: () => ( 2 + 4 ) }; -var output = Mustache.render("{{title}} spends {{calc}}", view); +const output = Mustache.render("{{title}} spends {{calc}}", view); ``` -In this example, the `Mustache.render` function takes two parameters: 1) the [mustache](http://mustache.github.com/) template and 2) a `view` object that contains the data and code needed to render the template. +In this example, the `Mustache.render` function takes two parameters: 1) the [mustache](http://mustache.github.io/) template and 2) a `view` object that contains the data and code needed to render the template. ## Templates -A [mustache](http://mustache.github.com/) template is a string that contains any number of mustache tags. Tags are indicated by the double mustaches that surround them. `{{person}}` is a tag, as is `{{#person}}`. In both examples we refer to `person` as the tag's key. There are several types of tags available in mustache.js, described below. +A [mustache](http://mustache.github.io/) template is a string that contains any number of mustache tags. Tags are indicated by the double mustaches that surround them. `{{person}}` is a tag, as is `{{#person}}`. In both examples we refer to `person` as the tag's key. There are several types of tags available in mustache.js, described below. There are several techniques that can be used to load templates and hand them to mustache.js, here are two of them: #### Include Templates -If you need a template for a dynamic part in a static website, you can consider including the template in the static HTML file to avoid loading templates separately. Here's a small example using `jQuery`: +If you need a template for a dynamic part in a static website, you can consider including the template in the static HTML file to avoid loading templates separately. Here's a small example: + +```js +// file: render.js + +function renderHello() { + const template = document.getElementById('template').innerHTML; + const rendered = Mustache.render(template, { name: 'Luke' }); + document.getElementById('target').innerHTML = rendered; +} +``` ```html - -
Loading...
- - + +
Loading...
+ + + + + ``` -```js -function loadUser() { - var template = $('#template').html(); - Mustache.parse(template); // optional, speeds up future uses - var rendered = Mustache.render(template, {name: "Luke"}); - $('#target').html(rendered); -} -``` - #### Load External Templates -If your templates reside in individual files, you can load them asynchronously and render them when they arrive. Another example using `jQuery`: +If your templates reside in individual files, you can load them asynchronously and render them when they arrive. Another example using [fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch): ```js -function loadUser() { - $.get('template.mst', function(template) { - var rendered = Mustache.render(template, {name: "Luke"}); - $('#target').html(rendered); - }); +function renderHello() { + fetch('template.mustache') + .then((response) => response.text()) + .then((template) => { + const rendered = Mustache.render(template, { name: 'Luke' }); + document.getElementById('target').innerHTML = rendered; + }); } ``` @@ -106,7 +104,9 @@ The most basic tag type is a simple variable. A `{{name}}` tag renders the value All variables are HTML-escaped by default. If you want to render unescaped HTML, use the triple mustache: `{{{name}}}`. You can also use `&` to unescape a variable. -If you want `{{name}}` _not_ to be interpreted as a mustache tag, but rather to appear exactly as `{{name}}` in the output, you must change and then restore the default delimiter. See the ["Set Delimiter'](https://github.com/janl/mustache.js#set-delimiter) section for more information about custom delimiters. +If you'd like to change HTML-escaping behavior globally (for example, to template non-HTML formats), you can override Mustache's escape function. For example, to disable all escaping: `Mustache.escape = function(text) {return text;};`. + +If you want `{{name}}` _not_ to be interpreted as a mustache tag, but rather to appear exactly as `{{name}}` in the output, you must change and then restore the default delimiter. See the [Custom Delimiters](#custom-delimiters) section for more information. View: @@ -119,7 +119,7 @@ View: Template: -```html +``` * {{name}} * {{age}} * {{company}} @@ -171,7 +171,7 @@ Output: ### Sections -Sections render blocks of text one or more times, depending on the value of the key in the current context. +Sections render blocks of text zero or more times, depending on the value of the key in the current context. A section begins with a pound and ends with a slash. That is, `{{#person}}` begins a `person` section, while `{{/person}}` ends it. The text between the two tags is referred to as that section's "block". @@ -419,13 +419,36 @@ Mustache.render(template, view, { }); ``` -### Set Delimiter +### Custom Delimiters + +Custom delimiters can be used in place of `{{` and `}}` by setting the new values in JavaScript or in templates. + +#### Setting in JavaScript + +The `Mustache.tags` property holds an array consisting of the opening and closing tag values. Set custom values by passing a new array of tags to `render()`, which gets honored over the default values, or by overriding the `Mustache.tags` property itself: + +```js +const customTags = [ '<%', '%>' ]; +``` + +##### Pass Value into Render Method +```js +Mustache.render(template, view, {}, customTags); +``` + +##### Override Tags Property +```js +Mustache.tags = customTags; +// Subsequent parse() and render() calls will use customTags +``` + +#### Setting in Templates Set Delimiter tags start with an equals sign and change the tag delimiters from `{{` and `}}` to custom strings. Consider the following contrived example: -``` +```html+erb * {{ default_tags }} {{=<% %>=}} * <% erb_style_tags %> @@ -435,7 +458,7 @@ Consider the following contrived example: Here we have a list with three items. The first item uses the default tag style, the second uses ERB style as defined by the Set Delimiter tag, and the third returns to the default style after yet another Set Delimiter declaration. -According to [ctemplates](http://google-ctemplate.googlecode.com/svn/trunk/doc/howto.html), this "is useful for languages like TeX, where double-braces may occur in the text and are awkward to use for markup." +According to [ctemplates](https://htmlpreview.github.io/?https://raw.githubusercontent.com/OlafvdSpek/ctemplate/master/doc/howto.html), this "is useful for languages like TeX, where double-braces may occur in the text and are awkward to use for markup." Custom delimiters may not contain whitespace or the equals sign. @@ -450,33 +473,19 @@ Mustache.parse(template); Mustache.render(template, view); ``` -## Plugins for JavaScript Libraries - -mustache.js may be built specifically for several different client libraries, including the following: - - - [jQuery](http://jquery.com/) - - [MooTools](http://mootools.net/) - - [Dojo](http://www.dojotoolkit.org/) - - [YUI](http://developer.yahoo.com/yui/) - - [qooxdoo](http://qooxdoo.org/) - -These may be built using [Rake](http://rake.rubyforge.org/) and one of the following commands: - - $ rake jquery - $ rake mootools - $ rake dojo - $ rake yui3 - $ rake qooxdoo - ## Command line tool -mustache.js is shipped with a node based command line tool. It might be installed as a global tool on your computer to render a mustache template of some kind +mustache.js is shipped with a Node.js based command line tool. It might be installed as a global tool on your computer to render a mustache template of some kind ```bash $ npm install -g mustache + $ mustache dataView.json myTemplate.mustache > output.html +``` + +also supports stdin. -# also supports stdin +```bash $ cat dataView.json | mustache - myTemplate.mustache > output.html ``` @@ -485,6 +494,7 @@ or as a package.json `devDependency` in a build process maybe? ```bash $ npm install mustache --save-dev ``` + ```json { "scripts": { @@ -496,25 +506,55 @@ $ npm install mustache --save-dev $ npm run build ``` -The command line tool is basically a wrapper around `Mustache.render` so you get all the aformentioned features. +The command line tool is basically a wrapper around `Mustache.render` so you get all the features. -## Testing +If your templates use partials you should pass paths to partials using `-p` flag: -In order to run the tests you'll need to install [node](http://nodejs.org/). +```bash +$ mustache -p path/to/partial1.mustache -p path/to/partial2.mustache dataView.json myTemplate.mustache +``` -You also need to install the sub module containing [Mustache specifications](http://github.com/mustache/spec) in the project root. +## Plugins for JavaScript Libraries - $ git submodule init - $ git submodule update +mustache.js may be built specifically for several different client libraries, including the following: -Install dependencies. + - [jQuery](http://jquery.com/) + - [MooTools](http://mootools.net/) + - [Dojo](http://www.dojotoolkit.org/) + - [YUI](http://developer.yahoo.com/yui/) + - [qooxdoo](http://qooxdoo.org/) + +These may be built using [Rake](http://rake.rubyforge.org/) and one of the following commands: +```bash +$ rake jquery +$ rake mootools +$ rake dojo +$ rake yui3 +$ rake qooxdoo +``` - $ npm install +## TypeScript -Then run the tests. +Since the source code of this package is written in JavaScript, we follow the [TypeScript publishing docs](https://www.typescriptlang.org/docs/handbook/declaration-files/publishing.html) preferred approach +by having type definitions available via [@types/mustache](https://www.npmjs.com/package/@types/mustache). - $ npm test +## Testing + +In order to run the tests you'll need to install [Node.js](http://nodejs.org/). +You also need to install the sub module containing [Mustache specifications](http://github.com/mustache/spec) in the project root. +```bash +$ git submodule init +$ git submodule update +``` +Install dependencies. +```bash +$ npm install +``` +Then run the tests. +```bash +$ npm test +``` The test suite consists of both unit and integration tests. If a template isn't rendering correctly for you, you can make a test for it by doing the following: 1. Create a template file named `mytest.mustache` in the `test/_files` @@ -526,24 +566,33 @@ The test suite consists of both unit and integration tests. If a template isn't directory. Then, you can run the test with: - - $ TEST=mytest npm run test-render +```bash +$ TEST=mytest npm run test-render +``` ### Browser tests -Browser tests are not included in `npm test` as they run for too long, although they are runned automatically on Travis when merged into master. Run browser tests locally in any browser: +Browser tests are not included in `npm test` as they run for too long, although they are ran automatically on Travis when merged into master. Run browser tests locally in any browser: +```bash +$ npm run test-browser-local +``` +then point your browser to `http://localhost:8080/__zuul` - $ npm run test-browser-local +## Who uses mustache.js? -then point your browser to `http://localhost:8080/__zuul` +An updated list of mustache.js users is kept [on the Github wiki](https://github.com/janl/mustache.js/wiki/Beard-Competition). Add yourself or your company if you use mustache.js! -### Troubleshooting +## Contributing -#### npm install fails +mustache.js is a mature project, but it continues to actively invite maintainers. You can help out a high-profile project that is used in a lot of places on the web. No big commitment required, if all you do is review a single [Pull Request](https://github.com/janl/mustache.js/pulls), you are a maintainer. And a hero. -Ensure to have a recent version of npm installed. While developing this project requires npm with support for `^` version ranges. +### Your First Contribution - $ npm install -g npm +- review a [Pull Request](https://github.com/janl/mustache.js/pulls) +- fix an [Issue](https://github.com/janl/mustache.js/issues) +- update the [documentation](https://github.com/janl/mustache.js#usage) +- make a website +- write a tutorial ## Thanks @@ -567,6 +616,6 @@ mustache.js wouldn't kick ass if it weren't for these fine souls: * Ross Boucher / boucher * Matt Sanford / mzsanford * Ben Cherry / bcherry - * Michael Jackson / mjijackson + * Michael Jackson / mjackson * Phillip Johnsen / phillipj * David da Silva Contín / dasilvacontin diff --git a/Rakefile b/Rakefile index c01908732..2540c2804 100644 --- a/Rakefile +++ b/Rakefile @@ -7,31 +7,14 @@ def minified_file ENV['FILE'] || 'mustache.min.js' end -task :install_mocha do - sh "npm install -g mocha" if `which mocha`.empty? -end - -task :install_uglify do - sh "npm install -g uglify-js" if `which uglifyjs`.empty? -end - -task :install_jshint do - sh "npm install -g jshint" if `which jshint`.empty? -end - desc "Run all tests" -task :test => :install_mocha do - sh "mocha test" -end - -desc "Make a compressed build in #{minified_file}" -task :minify => :install_uglify do - sh "uglifyjs mustache.js > #{minified_file}" +task :test do + sh "./node_modules/.bin/mocha test" end desc "Run JSHint" -task :hint => :install_jshint do - sh "jshint mustache.js" +task :hint do + sh "./node_modules/.bin/jshint mustache.js" end # Creates a task that uses the various template wrappers to make a wrapped diff --git a/bin/mustache b/bin/mustache index a88c9b4f9..6db073f5d 100755 --- a/bin/mustache +++ b/bin/mustache @@ -1,23 +1,33 @@ #!/usr/bin/env node -var fs = require('fs'); +var fs = require('fs'), + path = require('path'); var Mustache = require('..'); var pkg = require('../package'); +var partials = {}; + +var partialsPaths = []; +var partialArgIndex = -1; + +while ((partialArgIndex = process.argv.indexOf('-p')) > -1) { + partialsPaths.push(process.argv.splice(partialArgIndex, 2)[1]); +} var viewArg = process.argv[2]; var templateArg = process.argv[3]; +var outputArg = process.argv[4]; if (hasVersionArg()) { return console.log(pkg.version); } if (!templateArg || !viewArg) { - console.error('Syntax: mustache