├── .husky ├── pre-commit └── commit-msg ├── test ├── fixtures │ ├── broken.coffee │ ├── local-file.coffee │ ├── bar.js │ ├── bare.js │ ├── baz.js │ ├── simple.js │ ├── bare.coffee │ ├── foo.coffee │ └── baz.litcoffee ├── helpers │ ├── getErrors.js │ ├── getWarnings.js │ ├── getModuleSource.js │ ├── compile.js │ ├── readAssets.js │ ├── index.js │ ├── normalizeErrors.js │ ├── testLoader.js │ ├── execute.js │ ├── readAsset.js │ └── getCompiler.js ├── cjs.test.js ├── validate-options.test.js ├── loader.test.js └── __snapshots__ │ └── loader.test.js.snap ├── .prettierignore ├── .gitattributes ├── src ├── cjs.js ├── options.json ├── CoffeeScriptError.js └── index.js ├── lint-staged.config.js ├── commitlint.config.js ├── eslint.config.mjs ├── .editorconfig ├── .gitignore ├── .cspell.json ├── babel.config.js ├── .github └── workflows │ ├── dependency-review.yml │ └── nodejs.yml ├── LICENSE ├── package.json ├── CHANGELOG.md └── README.md /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | lint-staged 2 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | commitlint --edit $1 2 | -------------------------------------------------------------------------------- /test/fixtures/broken.coffee: -------------------------------------------------------------------------------- 1 | broken;!; 2 | -------------------------------------------------------------------------------- /test/fixtures/local-file.coffee: -------------------------------------------------------------------------------- 1 | export default square = (x) -> x * x 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | /coverage 2 | /dist 3 | /node_modules 4 | /test/fixtures 5 | CHANGELOG.md -------------------------------------------------------------------------------- /test/fixtures/bar.js: -------------------------------------------------------------------------------- 1 | import foo from './broken.coffee'; 2 | 3 | export default foo; 4 | -------------------------------------------------------------------------------- /test/fixtures/bare.js: -------------------------------------------------------------------------------- 1 | import foo from './bare.coffee'; 2 | 3 | export default foo; 4 | -------------------------------------------------------------------------------- /test/fixtures/baz.js: -------------------------------------------------------------------------------- 1 | import foo from './baz.litcoffee'; 2 | 3 | export default foo; 4 | -------------------------------------------------------------------------------- /test/fixtures/simple.js: -------------------------------------------------------------------------------- 1 | import foo from './foo.coffee'; 2 | 3 | export default foo; 4 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | bin/* eol=lf 3 | yarn.lock -diff 4 | package-lock.json -diff -------------------------------------------------------------------------------- /src/cjs.js: -------------------------------------------------------------------------------- 1 | const loader = require("./index"); 2 | 3 | module.exports = loader.default; 4 | -------------------------------------------------------------------------------- /test/fixtures/bare.coffee: -------------------------------------------------------------------------------- 1 | outer = 1 2 | changeNumbers = -> 3 | inner = -1 4 | outer = 10 5 | inner = changeNumbers() 6 | -------------------------------------------------------------------------------- /lint-staged.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "*": ["prettier --write --ignore-unknown", "cspell"], 3 | "*.js": ["eslint --cache --fix"], 4 | }; 5 | -------------------------------------------------------------------------------- /test/helpers/getErrors.js: -------------------------------------------------------------------------------- 1 | import normalizeErrors from "./normalizeErrors"; 2 | 3 | export default (stats) => normalizeErrors(stats.compilation.errors); 4 | -------------------------------------------------------------------------------- /test/helpers/getWarnings.js: -------------------------------------------------------------------------------- 1 | import normalizeErrors from "./normalizeErrors"; 2 | 3 | export default (stats) => normalizeErrors(stats.compilation.warnings); 4 | -------------------------------------------------------------------------------- /src/options.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Coffee Loader options", 3 | "type": "object", 4 | "description": "Options for CoffeeScript.", 5 | "additionalProperties": true 6 | } 7 | -------------------------------------------------------------------------------- /test/cjs.test.js: -------------------------------------------------------------------------------- 1 | import src from "../src"; 2 | import cjs from "../src/cjs"; 3 | 4 | describe("cjs", () => { 5 | it("should exported", () => { 6 | expect(cjs).toEqual(src); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /test/helpers/getModuleSource.js: -------------------------------------------------------------------------------- 1 | export default (id, stats) => { 2 | const { modules } = stats.toJson({ source: true }); 3 | const module = modules.find((m) => m.name === id); 4 | 5 | return module.source; 6 | }; 7 | -------------------------------------------------------------------------------- /src/CoffeeScriptError.js: -------------------------------------------------------------------------------- 1 | class CoffeeScriptError extends Error { 2 | constructor(error) { 3 | super(error); 4 | 5 | this.name = "CoffeeScriptError"; 6 | } 7 | } 8 | 9 | export default CoffeeScriptError; 10 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ["@commitlint/config-conventional"], 3 | rules: { 4 | "header-max-length": [0], 5 | "body-max-line-length": [0], 6 | "footer-max-line-length": [0], 7 | }, 8 | }; 9 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "eslint/config"; 2 | import configs from "eslint-config-webpack/configs.js"; 3 | 4 | export default defineConfig([ 5 | { 6 | extends: [configs["recommended-dirty"]], 7 | }, 8 | ]); 9 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false -------------------------------------------------------------------------------- /test/helpers/compile.js: -------------------------------------------------------------------------------- 1 | export default (compiler) => 2 | new Promise((resolve, reject) => { 3 | compiler.run((error, stats) => { 4 | if (error) { 5 | return reject(error); 6 | } 7 | 8 | return resolve(stats); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | logs 3 | *.log 4 | npm-debug.log* 5 | .eslintcache 6 | /coverage 7 | /dist 8 | /local 9 | /reports 10 | /node_modules 11 | .DS_Store 12 | Thumbs.db 13 | .idea 14 | *.iml 15 | .vscode 16 | *.sublime-project 17 | *.sublime-workspace 18 | .cspellcache 19 | -------------------------------------------------------------------------------- /test/helpers/readAssets.js: -------------------------------------------------------------------------------- 1 | import readAsset from "./readAsset"; 2 | 3 | export default function readAssets(compiler, stats) { 4 | const assets = {}; 5 | 6 | for (const asset of Object.keys(stats.compilation.assets)) { 7 | assets[asset] = readAsset(asset, compiler, stats); 8 | } 9 | 10 | return assets; 11 | } 12 | -------------------------------------------------------------------------------- /.cspell.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2", 3 | "language": "en,en-gb", 4 | "words": ["commitlint", "hspace", "Bublé", "Koppers", "sokra", "memfs"], 5 | "ignorePaths": [ 6 | "CHANGELOG.md", 7 | "package.json", 8 | "dist/**", 9 | "**/__snapshots__/**", 10 | "package-lock.json", 11 | "node_modules", 12 | "coverage", 13 | "*.log" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | const MIN_BABEL_VERSION = 7; 2 | 3 | module.exports = (api) => { 4 | api.assertVersion(MIN_BABEL_VERSION); 5 | api.cache(true); 6 | 7 | return { 8 | presets: [ 9 | [ 10 | "@babel/preset-env", 11 | { 12 | targets: { 13 | node: "18.12.0", 14 | }, 15 | }, 16 | ], 17 | ], 18 | }; 19 | }; 20 | -------------------------------------------------------------------------------- /.github/workflows/dependency-review.yml: -------------------------------------------------------------------------------- 1 | name: "Dependency Review" 2 | on: [pull_request] 3 | 4 | permissions: 5 | contents: read 6 | 7 | jobs: 8 | dependency-review: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: "Checkout Repository" 12 | uses: actions/checkout@v5 13 | - name: "Dependency Review" 14 | uses: actions/dependency-review-action@v4 15 | -------------------------------------------------------------------------------- /test/helpers/index.js: -------------------------------------------------------------------------------- 1 | export { default as compile } from "./compile"; 2 | export { default as getCompiler } from "./getCompiler"; 3 | export { default as execute } from "./execute"; 4 | export { default as getModuleSource } from "./getModuleSource"; 5 | export { default as getErrors } from "./getErrors"; 6 | export { default as normalizeErrors } from "./normalizeErrors"; 7 | export { default as getWarnings } from "./getWarnings"; 8 | export { default as readsAssets } from "./readAssets"; 9 | export { default as readAsset } from "./readAsset"; 10 | -------------------------------------------------------------------------------- /test/helpers/normalizeErrors.js: -------------------------------------------------------------------------------- 1 | function removeCWD(str) { 2 | const isWin = process.platform === "win32"; 3 | let cwd = process.cwd(); 4 | 5 | if (isWin) { 6 | str = str.replaceAll("\\", "/"); 7 | 8 | cwd = cwd.replaceAll("\\", "/"); 9 | } 10 | 11 | return str 12 | .replace(/\(from .*?\)/, "(from `replaced original path`)") 13 | .replaceAll(new RegExp(cwd, "g"), ""); 14 | } 15 | 16 | export default (errors) => 17 | errors.map((error) => 18 | removeCWD(error.toString().split("\n").slice(0, 2).join("\n")), 19 | ); 20 | -------------------------------------------------------------------------------- /test/helpers/testLoader.js: -------------------------------------------------------------------------------- 1 | const path = require("node:path"); 2 | 3 | function testLoader(source, sourceMap) { 4 | if (sourceMap) { 5 | sourceMap.sources = sourceMap.sources.map((item) => { 6 | if (path.isAbsolute(item)) { 7 | return `/absolute/path/to/${path 8 | .relative(process.cwd(), item) 9 | .replaceAll("\\", "/")}`; 10 | } 11 | 12 | return item; 13 | }); 14 | } 15 | 16 | return `module.exports = ${JSON.stringify({ source, sourceMap })}`; 17 | } 18 | 19 | module.exports = testLoader; 20 | -------------------------------------------------------------------------------- /test/helpers/execute.js: -------------------------------------------------------------------------------- 1 | import Module from "node:module"; 2 | import path from "node:path"; 3 | 4 | const parentModule = module; 5 | 6 | export default (code) => { 7 | const resource = "test.js"; 8 | const module = new Module(resource, parentModule); 9 | 10 | module.paths = Module._nodeModulePaths( 11 | path.resolve(__dirname, "../fixtures"), 12 | ); 13 | module.filename = resource; 14 | 15 | module._compile(`module.exports = ${code};`, resource); 16 | 17 | return module.exports.__esModule ? module.exports.default : module.exports; 18 | }; 19 | -------------------------------------------------------------------------------- /test/helpers/readAsset.js: -------------------------------------------------------------------------------- 1 | import path from "node:path"; 2 | 3 | export default (asset, compiler, stats) => { 4 | const usedFs = compiler.outputFileSystem; 5 | const outputPath = stats.compilation.outputOptions.path; 6 | 7 | let data = ""; 8 | let targetFile = asset; 9 | 10 | const queryStringIdx = targetFile.indexOf("?"); 11 | 12 | if (queryStringIdx >= 0) { 13 | targetFile = targetFile.slice(0, queryStringIdx); 14 | } 15 | 16 | try { 17 | data = usedFs.readFileSync(path.join(outputPath, targetFile)).toString(); 18 | } catch (error) { 19 | data = error.toString(); 20 | } 21 | 22 | return data; 23 | }; 24 | -------------------------------------------------------------------------------- /test/fixtures/foo.coffee: -------------------------------------------------------------------------------- 1 | import * as local from './local-file.coffee'; 2 | 3 | # Assignment: 4 | number = 42 5 | opposite = true 6 | 7 | # Conditions: 8 | number = -42 if opposite 9 | 10 | # Functions: 11 | square = (x) -> x * x 12 | 13 | # Arrays: 14 | list = [1, 2, 3, 4, 5] 15 | 16 | # Objects: 17 | math = 18 | root: Math.sqrt 19 | square: square 20 | cube: (x) -> x * square x 21 | 22 | # Splats: 23 | race = (winner, runners...) -> 24 | print winner, runners 25 | 26 | # Existence: 27 | alert "I knew it!" if elvis? 28 | 29 | # Array comprehensions: 30 | cubes = (math.cube num for num in list) 31 | 32 | export default { number, opposite, square, list, math, race, cubes, local } 33 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License http://www.opensource.org/licenses/mit-license.php 3 | Author Tobias Koppers @sokra 4 | */ 5 | import { compile } from "coffeescript"; 6 | 7 | import CoffeeScriptError from "./CoffeeScriptError"; 8 | import schema from "./options.json"; 9 | 10 | export default function loader(source) { 11 | const options = this.getOptions(schema); 12 | const callback = this.async(); 13 | const useSourceMap = 14 | typeof options.sourceMap === "boolean" ? options.sourceMap : this.sourceMap; 15 | 16 | let result; 17 | 18 | try { 19 | result = compile(source, { 20 | sourceMap: useSourceMap, 21 | bare: true, 22 | ...options, 23 | filename: this.resourcePath, 24 | }); 25 | } catch (error) { 26 | callback(new CoffeeScriptError(error)); 27 | 28 | return; 29 | } 30 | 31 | let map; 32 | 33 | if (useSourceMap && result.v3SourceMap) { 34 | map = JSON.parse(result.v3SourceMap); 35 | 36 | delete map.file; 37 | 38 | result = result.js; 39 | } 40 | 41 | callback(null, result, map); 42 | } 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright JS Foundation and other contributors 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | 'Software'), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 20 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /test/helpers/getCompiler.js: -------------------------------------------------------------------------------- 1 | import path from "node:path"; 2 | 3 | import { Volume, createFsFromVolume } from "memfs"; 4 | import webpack from "webpack"; 5 | 6 | export default (fixture, loaderOptions = {}, config = {}) => { 7 | const fullConfig = { 8 | mode: "development", 9 | devtool: config.devtool || false, 10 | context: path.resolve(__dirname, "../fixtures"), 11 | entry: path.resolve(__dirname, "../fixtures", fixture), 12 | output: { 13 | path: path.resolve(__dirname, "../outputs"), 14 | filename: "[name].bundle.js", 15 | chunkFilename: "[name].chunk.js", 16 | library: "coffeeLoaderExport", 17 | }, 18 | module: { 19 | rules: [ 20 | { 21 | test: /\.(coffee|litcoffee)$/i, 22 | use: [ 23 | { 24 | loader: require.resolve("./testLoader.js"), 25 | }, 26 | { 27 | loader: path.resolve(__dirname, "../../src"), 28 | options: loaderOptions || {}, 29 | }, 30 | ], 31 | }, 32 | ], 33 | }, 34 | plugins: [], 35 | ...config, 36 | }; 37 | 38 | const compiler = webpack(fullConfig); 39 | 40 | if (!config.outputFileSystem) { 41 | const outputFileSystem = createFsFromVolume(new Volume()); 42 | // Todo remove when we drop webpack@4 support 43 | outputFileSystem.join = path.join.bind(path); 44 | 45 | compiler.outputFileSystem = outputFileSystem; 46 | } 47 | 48 | return compiler; 49 | }; 50 | -------------------------------------------------------------------------------- /test/validate-options.test.js: -------------------------------------------------------------------------------- 1 | import { compile, getCompiler } from "./helpers"; 2 | 3 | describe("validate options", () => { 4 | const tests = { 5 | bare: { 6 | success: [true, false], 7 | // failure: [false, ''], 8 | }, 9 | sourceMap: { 10 | success: [true, false], 11 | // failure: ['true'], 12 | }, 13 | }; 14 | 15 | function stringifyValue(value) { 16 | if ( 17 | Array.isArray(value) || 18 | (value && typeof value === "object" && value.constructor === Object) 19 | ) { 20 | return JSON.stringify(value); 21 | } 22 | 23 | return value; 24 | } 25 | 26 | async function createTestCase(key, value, type) { 27 | it(`should ${ 28 | type === "success" ? "successfully validate" : "throw an error on" 29 | } the "${key}" option with "${stringifyValue(value)}" value`, async () => { 30 | const compiler = getCompiler("simple.js", { [key]: value }); 31 | 32 | let stats; 33 | 34 | try { 35 | stats = await compile(compiler); 36 | } finally { 37 | if (type === "success") { 38 | expect(stats.hasErrors()).toBe(false); 39 | } else if (type === "failure") { 40 | const { 41 | compilation: { errors }, 42 | } = stats; 43 | 44 | expect(errors).toHaveLength(1); 45 | expect(() => { 46 | throw new Error(errors[0].error.message); 47 | }).toThrowErrorMatchingSnapshot(); 48 | } 49 | } 50 | }); 51 | } 52 | 53 | for (const [key, values] of Object.entries(tests)) { 54 | for (const type of Object.keys(values)) { 55 | for (const value of values[type]) { 56 | createTestCase(key, value, type); 57 | } 58 | } 59 | } 60 | }); 61 | -------------------------------------------------------------------------------- /.github/workflows/nodejs.yml: -------------------------------------------------------------------------------- 1 | name: coffee-loader 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - next 8 | pull_request: 9 | branches: 10 | - main 11 | - next 12 | 13 | permissions: 14 | contents: read 15 | 16 | jobs: 17 | lint: 18 | name: Lint - ${{ matrix.os }} - Node v${{ matrix.node-version }} 19 | 20 | env: 21 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 22 | 23 | strategy: 24 | matrix: 25 | os: [ubuntu-latest] 26 | node-version: [lts/*] 27 | 28 | runs-on: ${{ matrix.os }} 29 | 30 | concurrency: 31 | group: lint-${{ matrix.os }}-v${{ matrix.node-version }}-${{ github.ref }} 32 | cancel-in-progress: true 33 | 34 | steps: 35 | - uses: actions/checkout@v5 36 | with: 37 | fetch-depth: 0 38 | 39 | - name: Use Node.js ${{ matrix.node-version }} 40 | uses: actions/setup-node@v4 41 | with: 42 | node-version: ${{ matrix.node-version }} 43 | cache: "npm" 44 | 45 | - name: Install dependencies 46 | run: npm ci 47 | 48 | - name: Lint 49 | run: npm run lint 50 | 51 | - name: Security audit 52 | run: npm run security 53 | 54 | - name: Validate PR commits with commitlint 55 | if: github.event_name == 'pull_request' 56 | run: npx commitlint --from ${{ github.event.pull_request.head.sha }}~${{ github.event.pull_request.commits }} --to ${{ github.event.pull_request.head.sha }} --verbose 57 | 58 | test: 59 | name: Test - ${{ matrix.os }} - Node v${{ matrix.node-version }}, Webpack ${{ matrix.webpack-version }} 60 | 61 | strategy: 62 | matrix: 63 | os: [ubuntu-latest, windows-latest, macos-latest] 64 | node-version: [18.x, 20.x, 22.x, 24.x] 65 | webpack-version: [latest] 66 | 67 | runs-on: ${{ matrix.os }} 68 | 69 | concurrency: 70 | group: test-${{ matrix.os }}-v${{ matrix.node-version }}-${{ matrix.webpack-version }}-${{ github.ref }} 71 | cancel-in-progress: true 72 | 73 | steps: 74 | - uses: actions/checkout@v5 75 | 76 | - name: Use Node.js ${{ matrix.node-version }} 77 | uses: actions/setup-node@v4 78 | with: 79 | node-version: ${{ matrix.node-version }} 80 | cache: "npm" 81 | 82 | - name: Install dependencies 83 | run: npm ci 84 | 85 | - name: Install webpack ${{ matrix.webpack-version }} 86 | if: matrix.webpack-version != 'latest' 87 | run: npm i webpack@${{ matrix.webpack-version }} 88 | 89 | - name: Run tests for webpack version ${{ matrix.webpack-version }} 90 | run: npm run test:coverage -- --ci 91 | 92 | - name: Submit coverage data to codecov 93 | uses: codecov/codecov-action@v5 94 | with: 95 | token: ${{ secrets.CODECOV_TOKEN }} 96 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "coffee-loader", 3 | "version": "5.0.0", 4 | "description": "coffee loader module for webpack", 5 | "keywords": [ 6 | "webpack" 7 | ], 8 | "homepage": "https://github.com/webpack/coffee-loader", 9 | "bugs": "https://github.com/webpack/coffee-loader/issues", 10 | "repository": "webpack/coffee-loader", 11 | "funding": { 12 | "type": "opencollective", 13 | "url": "https://opencollective.com/webpack" 14 | }, 15 | "license": "MIT", 16 | "author": "Tobias Koppers @sokra", 17 | "main": "dist/cjs.js", 18 | "files": [ 19 | "dist" 20 | ], 21 | "scripts": { 22 | "start": "npm run build -- -w", 23 | "clean": "del-cli dist", 24 | "prebuild": "npm run clean", 25 | "build": "cross-env NODE_ENV=production babel src -d dist --copy-files", 26 | "commitlint": "commitlint --from=main", 27 | "security": "npm audit --production", 28 | "lint:prettier": "prettier --list-different .", 29 | "lint:js": "eslint --cache .", 30 | "lint:spelling": "cspell --no-must-find-files --cache --quiet \"**/*.*\"", 31 | "lint": "npm-run-all -l -p \"lint:**\"", 32 | "fix:js": "npm run lint:js -- --fix", 33 | "fix:prettier": "npm run lint:prettier -- --write", 34 | "fix": "npm-run-all -l fix:js fix:prettier", 35 | "test:only": "cross-env NODE_ENV=test jest", 36 | "test:watch": "npm run test:only -- --watch", 37 | "test:coverage": "npm run test:only -- --collectCoverageFrom=\"src/**/*.js\" --coverage", 38 | "pretest": "npm run lint", 39 | "test": "npm run test:coverage", 40 | "prepare": "husky && npm run build", 41 | "release": "standard-version" 42 | }, 43 | "devDependencies": { 44 | "@babel/cli": "^7.24.7", 45 | "@babel/core": "^7.24.7", 46 | "@babel/preset-env": "^7.24.7", 47 | "@commitlint/cli": "^19.3.0", 48 | "@commitlint/config-conventional": "^19.2.2", 49 | "@eslint/js": "^9.32.0", 50 | "@eslint/markdown": "^7.1.0", 51 | "@stylistic/eslint-plugin": "^5.2.2", 52 | "babel-jest": "^30.0.0", 53 | "coffeescript": "^2.7.0", 54 | "cross-env": "^7.0.3", 55 | "cspell": "^8.9.1", 56 | "del": "^7.1.0", 57 | "del-cli": "^5.1.0", 58 | "eslint": "^9.30.1", 59 | "eslint-config-prettier": "^10.1.5", 60 | "eslint-config-webpack": "^4.3.0", 61 | "eslint-plugin-import": "^2.32.0", 62 | "eslint-plugin-jest": "^29.0.1", 63 | "eslint-plugin-n": "^17.21.0", 64 | "eslint-plugin-prettier": "^5.5.3", 65 | "eslint-plugin-unicorn": "^60.0.0", 66 | "globals": "^16.3.0", 67 | "husky": "^9.1.3", 68 | "jest": "^30.0.0", 69 | "lint-staged": "^15.2.7", 70 | "memfs": "^4.9.3", 71 | "npm-run-all": "^4.1.5", 72 | "prettier": "^3.3.2", 73 | "standard-version": "^9.3.2", 74 | "webpack": "^5.92.1" 75 | }, 76 | "peerDependencies": { 77 | "coffeescript": ">= 2.0.0", 78 | "webpack": "^5.0.0" 79 | }, 80 | "engines": { 81 | "node": ">= 18.12.0" 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. 4 | 5 | ## [5.0.0](https://github.com/webpack-contrib/coffee-loader/compare/v4.0.0...v5.0.0) (2024-01-15) 6 | 7 | 8 | ### ⚠ BREAKING CHANGES 9 | 10 | * minimum supported Node.js version is `18.12.0` ([#174](https://github.com/webpack-contrib/coffee-loader/issues/174)) ([1d4adfd](https://github.com/webpack-contrib/coffee-loader/commit/1d4adfd0bd5c9d9f4e05c16e4d0c2caacca7644d)) 11 | 12 | ## [4.0.0](https://github.com/webpack-contrib/coffee-loader/compare/v3.0.0...v4.0.0) (2022-05-18) 13 | 14 | 15 | ### ⚠ BREAKING CHANGES 16 | 17 | * minimum supported `Node.js` version is `14.15.0` 18 | 19 | ## [3.0.0](https://github.com/webpack-contrib/coffee-loader/compare/v2.0.0...v3.0.0) (2021-05-11) 20 | 21 | 22 | ### ⚠ BREAKING CHANGES 23 | 24 | * minimum supported `Node.js` version is `12.13.0` 25 | 26 | ## [2.0.0](https://github.com/webpack-contrib/coffee-loader/compare/v1.0.1...v2.0.0) (2020-12-22) 27 | 28 | 29 | ### ⚠ BREAKING CHANGES 30 | 31 | * minimum supported webpack version is `5` 32 | 33 | ### [1.0.1](https://github.com/webpack-contrib/coffee-loader/compare/v1.0.0...v1.0.1) (2020-10-09) 34 | 35 | ### Chore 36 | 37 | * update `schema-utils` 38 | 39 | ### [1.0.0](https://github.com/webpack-contrib/coffee-loader/compare/v0.9.0...v1.0.0) (2020-05-22) 40 | 41 | ### BREAKING CHANGES 42 | 43 | * minimum required Node.js version is `10.13.0` 44 | * minimum required `webpack` version is `4.0.0` 45 | * minimum required `coffeescript` version is `2.0.0` 46 | * default value for the `sourceMap` option based on the value of the `compiler.devtool` option 47 | 48 | ### Features 49 | 50 | * respect the `compiler.devtool` value for the `sourceMap` option 51 | * developer can override CoffeeScript options 52 | 53 | ### Bug Fixes 54 | 55 | * fix error reporting 56 | 57 | 58 | # [0.9.0](https://github.com/webpack-contrib/coffee-loader/compare/v0.8.0...v0.9.0) (2017-10-25) 59 | 60 | 61 | ### Features 62 | 63 | * add `transpile` option (`options.transpile`) ([#47](https://github.com/webpack-contrib/coffee-loader/issues/47)) ([abaf498](https://github.com/webpack-contrib/coffee-loader/commit/abaf498)) 64 | 65 | 66 | 67 | 68 | # 0.8.0 (2017-08-23) 69 | 70 | 71 | ### Bug Fixes 72 | 73 | * **#25:** fix coffee-script dependency version ([@jacobthemyth](https://github.com/jacobthemyth)) ([69ebdf4](https://github.com/webpack-contrib/coffee-loader/commit/69ebdf4)) 74 | * **getOptions:** deprecation warn in loaderUtils ([#28](https://github.com/webpack-contrib/coffee-loader/issues/28)) ([4e6b430](https://github.com/webpack-contrib/coffee-loader/commit/4e6b430)) 75 | 76 | 77 | ### Features 78 | 79 | * add support for coffeescript 2 dependency ([#30](https://github.com/webpack-contrib/coffee-loader/issues/30)) ([e5c24cc](https://github.com/webpack-contrib/coffee-loader/commit/e5c24cc)) 80 | -------------------------------------------------------------------------------- /test/fixtures/baz.litcoffee: -------------------------------------------------------------------------------- 1 | The **Scope** class regulates lexical scoping within CoffeeScript. As you 2 | generate code, you create a tree of scopes in the same shape as the nested 3 | function bodies. Each scope knows about the variables declared within it, 4 | and has a reference to its parent enclosing scope. In this way, we know which 5 | variables are new and need to be declared with `var`, and which are shared 6 | with external scopes. 7 | 8 | exports.Scope = class Scope 9 | 10 | Initialize a scope with its parent, for lookups up the chain, 11 | as well as a reference to the **Block** node it belongs to, which is 12 | where it should declare its variables, a reference to the function that 13 | it belongs to, and a list of variables referenced in the source code 14 | and therefore should be avoided when generating variables. Also track comments 15 | that should be output as part of variable declarations. 16 | 17 | constructor: (@parent, @expressions, @method, @referencedVars) -> 18 | @variables = [{name: 'arguments', type: 'arguments'}] 19 | @comments = {} 20 | @positions = {} 21 | @utilities = {} unless @parent 22 | 23 | The `@root` is the top-level **Scope** object for a given file. 24 | 25 | @root = @parent?.root ? this 26 | 27 | Adds a new variable or overrides an existing one. 28 | 29 | add: (name, type, immediate) -> 30 | return @parent.add name, type, immediate if @shared and not immediate 31 | if Object::hasOwnProperty.call @positions, name 32 | @variables[@positions[name]].type = type 33 | else 34 | @positions[name] = @variables.push({name, type}) - 1 35 | 36 | When `super` is called, we need to find the name of the current method we're 37 | in, so that we know how to invoke the same method of the parent class. This 38 | can get complicated if super is being called from an inner function. 39 | `namedMethod` will walk up the scope tree until it either finds the first 40 | function object that has a name filled in, or bottoms out. 41 | 42 | namedMethod: -> 43 | return @method if @method?.name or !@parent 44 | @parent.namedMethod() 45 | 46 | Look up a variable name in lexical scope, and declare it if it does not 47 | already exist. 48 | 49 | find: (name, type = 'var') -> 50 | return yes if @check name 51 | @add name, type 52 | no 53 | 54 | Reserve a variable name as originating from a function parameter for this 55 | scope. No `var` required for internal references. 56 | 57 | parameter: (name) -> 58 | return if @shared and @parent.check name, yes 59 | @add name, 'param' 60 | 61 | Just check to see if a variable has already been declared, without reserving, 62 | walks up to the root scope. 63 | 64 | check: (name) -> 65 | !!(@type(name) or @parent?.check(name)) 66 | 67 | Generate a temporary variable name at the given index. 68 | 69 | temporary: (name, index, single=false) -> 70 | if single 71 | startCode = name.charCodeAt(0) 72 | endCode = 'z'.charCodeAt(0) 73 | diff = endCode - startCode 74 | newCode = startCode + index % (diff + 1) 75 | letter = String.fromCharCode(newCode) 76 | num = index // (diff + 1) 77 | "#{letter}#{num or ''}" 78 | else 79 | "#{name}#{index or ''}" 80 | 81 | Gets the type of a variable. 82 | 83 | type: (name) -> 84 | return v.type for v in @variables when v.name is name 85 | null 86 | 87 | If we need to store an intermediate result, find an available name for a 88 | compiler-generated variable. `_var`, `_var2`, and so on... 89 | 90 | freeVariable: (name, options={}) -> 91 | index = 0 92 | loop 93 | temp = @temporary name, index, options.single 94 | break unless @check(temp) or temp in @root.referencedVars 95 | index++ 96 | @add temp, 'var', yes if options.reserve ? true 97 | temp 98 | 99 | Ensure that an assignment is made at the top of this scope 100 | (or at the top-level scope, if requested). 101 | 102 | assign: (name, value) -> 103 | @add name, {value, assigned: yes}, yes 104 | @hasAssignments = yes 105 | 106 | Does this scope have any declared variables? 107 | 108 | hasDeclarations: -> 109 | !!@declaredVariables().length 110 | 111 | Return the list of variables first declared in this scope. 112 | 113 | declaredVariables: -> 114 | (v.name for v in @variables when v.type is 'var').sort() 115 | 116 | Return the list of assignments that are supposed to be made at the top 117 | of this scope. 118 | 119 | assignedVariables: -> 120 | "#{v.name} = #{v.type.value}" for v in @variables when v.type.assigned 121 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | 6 |
7 | 8 | [![npm][npm]][npm-url] 9 | [![node][node]][node-url] 10 | [![tests][tests]][tests-url] 11 | [![coverage][cover]][cover-url] 12 | [![discussion][discussion]][discussion-url] 13 | [![size][size]][size-url] 14 | 15 | # coffee-loader 16 | 17 | Compile [CoffeeScript](https://coffeescript.org/) to JavaScript. 18 | 19 | ## Getting Started 20 | 21 | To begin, you'll need to install `coffeescript` and `coffee-loader`: 22 | 23 | ```console 24 | npm install --save-dev coffeescript coffee-loader 25 | ``` 26 | 27 | or 28 | 29 | ```console 30 | yarn add -D coffeescript coffee-loader 31 | ``` 32 | 33 | or 34 | 35 | ```console 36 | pnpm add -D coffeescript coffee-loader 37 | ``` 38 | 39 | Then add the loader to your `webpack.config.js`. For example: 40 | 41 | **file.coffee** 42 | 43 | ```coffee 44 | # Assignment: 45 | number = 42 46 | opposite = true 47 | 48 | # Conditions: 49 | number = -42 if opposite 50 | 51 | # Functions: 52 | square = (x) -> x * x 53 | 54 | # Arrays: 55 | list = [1, 2, 3, 4, 5] 56 | 57 | # Objects: 58 | math = 59 | root: Math.sqrt 60 | square: square 61 | cube: (x) -> x * square x 62 | 63 | # Splats: 64 | race = (winner, runners...) -> 65 | print winner, runners 66 | 67 | # Existence: 68 | alert "I knew it!" if elvis? 69 | 70 | # Array comprehensions: 71 | cubes = (math.cube num for num in list) 72 | ``` 73 | 74 | **webpack.config.js** 75 | 76 | ```js 77 | module.exports = { 78 | module: { 79 | rules: [ 80 | { 81 | test: /\.coffee$/, 82 | loader: "coffee-loader", 83 | }, 84 | ], 85 | }, 86 | }; 87 | ``` 88 | 89 | Alternative usage: 90 | 91 | ```js 92 | import coffee from "coffee-loader!./file.coffee"; 93 | ``` 94 | 95 | Finally, run `webpack` using the method you normally use (e.g., via CLI or an npm script). 96 | 97 | ## Options 98 | 99 | Type: `Object` 100 | Default: `{ bare: true }` 101 | 102 | You can find all available CoffeeScript options [here](https://coffeescript.org/#nodejs-usage). 103 | 104 | For documentation on the `transpile` option, see [this section](https://coffeescript.org/#transpilation). 105 | 106 | > [!NOTE] 107 | > 108 | > The `sourceMap` option takes a value from the `compiler.devtool` value by default. 109 | 110 | > [!NOTE] 111 | > 112 | > The `filename` option takes a value from webpack loader API, but it's value will be ignored. 113 | 114 | **webpack.config.js** 115 | 116 | ```js 117 | module.exports = { 118 | module: { 119 | rules: [ 120 | { 121 | test: /\.coffee$/, 122 | loader: "coffee-loader", 123 | options: { 124 | bare: false, 125 | transpile: { 126 | presets: ["@babel/env"], 127 | }, 128 | }, 129 | }, 130 | ], 131 | }, 132 | }; 133 | ``` 134 | 135 | ## Examples 136 | 137 | ### CoffeeScript and Babel 138 | 139 | From CoffeeScript 2 documentation: 140 | 141 | > [!NOTE] 142 | > 143 | > CoffeeScript 2 generates JavaScript using the latest, modern syntax. 144 | > The runtime or browsers where you want your code to run might not support all of that syntax. 145 | > In that case, modern JavaScript needs to be converted into an older JavaScript that will run in older versions of Node or older browsers; for example: `{ a } = obj` into `a = obj.a`. 146 | > This conversion is done using transpilers like Babel, Bublé or Traceur Compiler. 147 | 148 | You'll need to install `@babel/core` and `@babel/preset-env` and then create a configuration file: 149 | 150 | ```console 151 | npm install --save-dev @babel/core @babel/preset-env 152 | echo '{ "presets": ["@babel/env"] }' > .babelrc 153 | ``` 154 | 155 | **webpack.config.js** 156 | 157 | ```js 158 | module.exports = { 159 | module: { 160 | rules: [ 161 | { 162 | test: /\.coffee$/, 163 | loader: "coffee-loader", 164 | options: { 165 | transpile: { 166 | presets: ["@babel/env"], 167 | }, 168 | }, 169 | }, 170 | ], 171 | }, 172 | }; 173 | ``` 174 | 175 | ### Literate CoffeeScript 176 | 177 | To use Literate CoffeeScript you should setup: 178 | 179 | **webpack.config.js** 180 | 181 | ```js 182 | module.exports = { 183 | module: { 184 | rules: [ 185 | { 186 | test: /\.coffee$/, 187 | loader: "coffee-loader", 188 | options: { 189 | literate: true, 190 | }, 191 | }, 192 | ], 193 | }, 194 | }; 195 | ``` 196 | 197 | ## Contributing 198 | 199 | Please take a moment to read our contributing guidelines if you haven't yet done so. 200 | 201 | [CONTRIBUTING](https://github.com/webpack/coffee-loader?tab=contributing-ov-file#contributing) 202 | 203 | ## License 204 | 205 | [MIT](./LICENSE) 206 | 207 | [npm]: https://img.shields.io/npm/v/coffee-loader.svg 208 | [npm-url]: https://npmjs.com/package/coffee-loader 209 | [node]: https://img.shields.io/node/v/coffee-loader.svg 210 | [node-url]: https://nodejs.org 211 | [tests]: https://github.com/webpack/coffee-loader/workflows/coffee-loader/badge.svg 212 | [tests-url]: https://github.com/webpack/coffee-loader/actions 213 | [cover]: https://codecov.io/gh/webpack/coffee-loader/branch/main/graph/badge.svg 214 | [cover-url]: https://codecov.io/gh/webpack/coffee-loader 215 | [discussion]: https://img.shields.io/github/discussions/webpack/webpack 216 | [discussion-url]: https://github.com/webpack/webpack/discussions 217 | [size]: https://packagephobia.now.sh/badge?p=coffee-loader 218 | [size-url]: https://packagephobia.now.sh/result?p=coffee-loader 219 | -------------------------------------------------------------------------------- /test/loader.test.js: -------------------------------------------------------------------------------- 1 | import coffeescript from "coffeescript"; 2 | 3 | import { 4 | compile, 5 | execute, 6 | getCompiler, 7 | getErrors, 8 | getModuleSource, 9 | getWarnings, 10 | } from "./helpers"; 11 | 12 | describe("loader", () => { 13 | it("should work", async () => { 14 | const compiler = getCompiler("simple.js"); 15 | const stats = await compile(compiler); 16 | const { source, sourceMap } = execute( 17 | getModuleSource("./foo.coffee", stats), 18 | ); 19 | 20 | expect(source).toMatchSnapshot("source"); 21 | expect(sourceMap).toMatchSnapshot("sourceMap"); 22 | expect(getErrors(stats)).toMatchSnapshot("errors"); 23 | expect(getWarnings(stats)).toMatchSnapshot("warnings"); 24 | }); 25 | 26 | it("should work and code without the top-level function safety wrapper", async () => { 27 | const compiler = getCompiler("bare.js"); 28 | const stats = await compile(compiler); 29 | const { source, sourceMap } = execute( 30 | getModuleSource("./bare.coffee", stats), 31 | ); 32 | 33 | expect(source).toMatchSnapshot("source"); 34 | expect(sourceMap).toMatchSnapshot("sourceMap"); 35 | expect(getErrors(stats)).toMatchSnapshot("errors"); 36 | expect(getWarnings(stats)).toMatchSnapshot("warnings"); 37 | }); 38 | 39 | it("should generate an error on broken code", async () => { 40 | const compiler = getCompiler("bar.js"); 41 | const stats = await compile(compiler); 42 | 43 | expect(getErrors(stats)).toMatchSnapshot("errors"); 44 | expect(getWarnings(stats)).toMatchSnapshot("warnings"); 45 | }); 46 | 47 | it("should work and support CoffeeScript options", async () => { 48 | coffeescript.patchStackTrace(); 49 | 50 | const compiler = getCompiler("simple.js", { 51 | bare: true, 52 | transpile: { 53 | presets: ["@babel/env"], 54 | }, 55 | }); 56 | const stats = await compile(compiler); 57 | const { source, sourceMap } = execute( 58 | getModuleSource("./foo.coffee", stats), 59 | ); 60 | 61 | expect(source).toMatchSnapshot("source"); 62 | expect(sourceMap).toMatchSnapshot("sourceMap"); 63 | expect(getErrors(stats)).toMatchSnapshot("errors"); 64 | expect(getWarnings(stats)).toMatchSnapshot("warnings"); 65 | }); 66 | 67 | it("should throw an error on invalid CoffeeScript options", async () => { 68 | const compiler = getCompiler("simple.js", { 69 | bar: true, 70 | transpile: { 71 | presets: ["@babel/env1"], 72 | }, 73 | }); 74 | const stats = await compile(compiler); 75 | 76 | expect(getErrors(stats)).toMatchSnapshot("errors"); 77 | expect(getWarnings(stats)).toMatchSnapshot("warnings"); 78 | }); 79 | 80 | it("should work and generate source maps (take value from the `sourceMap` option)", async () => { 81 | const compiler = getCompiler("simple.js", { sourceMap: true }); 82 | const stats = await compile(compiler); 83 | const { source, sourceMap } = execute( 84 | getModuleSource("./foo.coffee", stats), 85 | ); 86 | 87 | expect(source).toMatchSnapshot("source"); 88 | expect(sourceMap).toMatchSnapshot("sourceMap"); 89 | expect(getErrors(stats)).toMatchSnapshot("errors"); 90 | expect(getWarnings(stats)).toMatchSnapshot("warnings"); 91 | }); 92 | 93 | it("should work and not generate source maps (take value from the `sourceMap` option)", async () => { 94 | const compiler = getCompiler("simple.js", { sourceMap: false }); 95 | const stats = await compile(compiler); 96 | const { source, sourceMap } = execute( 97 | getModuleSource("./foo.coffee", stats), 98 | ); 99 | 100 | expect(source).toMatchSnapshot("source"); 101 | expect(sourceMap).toMatchSnapshot("sourceMap"); 102 | expect(getErrors(stats)).toMatchSnapshot("errors"); 103 | expect(getWarnings(stats)).toMatchSnapshot("warnings"); 104 | }); 105 | 106 | it("should work and generate source maps (take value from the `compiler.devtool` option)", async () => { 107 | const compiler = getCompiler("simple.js", {}, { devtool: "source-map" }); 108 | const stats = await compile(compiler); 109 | const { source, sourceMap } = execute( 110 | getModuleSource("./foo.coffee", stats), 111 | ); 112 | 113 | expect(source).toMatchSnapshot("source"); 114 | expect(sourceMap).toMatchSnapshot("sourceMap"); 115 | expect(getErrors(stats)).toMatchSnapshot("errors"); 116 | expect(getWarnings(stats)).toMatchSnapshot("warnings"); 117 | }); 118 | 119 | it("should work and not generate source maps (take value from the `compiler.devtool` option)", async () => { 120 | const compiler = getCompiler("simple.js", {}, { devtool: false }); 121 | const stats = await compile(compiler); 122 | const { source, sourceMap } = execute( 123 | getModuleSource("./foo.coffee", stats), 124 | ); 125 | 126 | expect(source).toMatchSnapshot("source"); 127 | expect(sourceMap).toMatchSnapshot("sourceMap"); 128 | expect(getErrors(stats)).toMatchSnapshot("errors"); 129 | expect(getWarnings(stats)).toMatchSnapshot("warnings"); 130 | }); 131 | 132 | it("should work and generate source maps (the `sourceMap` option prefer over the `compiler.devtool` option)", async () => { 133 | const compiler = getCompiler( 134 | "simple.js", 135 | { sourceMap: true }, 136 | { devtool: false }, 137 | ); 138 | const stats = await compile(compiler); 139 | const { source, sourceMap } = execute( 140 | getModuleSource("./foo.coffee", stats), 141 | ); 142 | 143 | expect(source).toMatchSnapshot("source"); 144 | expect(sourceMap).toMatchSnapshot("sourceMap"); 145 | expect(getErrors(stats)).toMatchSnapshot("errors"); 146 | expect(getWarnings(stats)).toMatchSnapshot("warnings"); 147 | }); 148 | 149 | it("should work and ignore unknown CoffeeScript options", async () => { 150 | const compiler = getCompiler("simple.js", { unknown: true }); 151 | const stats = await compile(compiler); 152 | const { source, sourceMap } = execute( 153 | getModuleSource("./foo.coffee", stats), 154 | ); 155 | 156 | expect(source).toMatchSnapshot("source"); 157 | expect(sourceMap).toMatchSnapshot("sourceMap"); 158 | expect(getErrors(stats)).toMatchSnapshot("errors"); 159 | expect(getWarnings(stats)).toMatchSnapshot("warnings"); 160 | }); 161 | 162 | it("should work for Literate CoffeeScript", async () => { 163 | const compiler = getCompiler("baz.js", { literate: true }); 164 | const stats = await compile(compiler); 165 | const { source, sourceMap } = execute( 166 | getModuleSource("./baz.litcoffee", stats), 167 | ); 168 | 169 | expect(source).toMatchSnapshot("source"); 170 | expect(sourceMap).toMatchSnapshot("sourceMap"); 171 | expect(getErrors(stats)).toMatchSnapshot("errors"); 172 | expect(getWarnings(stats)).toMatchSnapshot("warnings"); 173 | }); 174 | }); 175 | -------------------------------------------------------------------------------- /test/__snapshots__/loader.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing 2 | 3 | exports[`loader should generate an error on broken code: errors 1`] = ` 4 | [ 5 | "ModuleBuildError: Module build failed (from \`replaced original path\`): 6 | CoffeeScriptError: /test/fixtures/broken.coffee:1:9: error: unexpected ;", 7 | ] 8 | `; 9 | 10 | exports[`loader should generate an error on broken code: warnings 1`] = `[]`; 11 | 12 | exports[`loader should throw an error on invalid CoffeeScript options: errors 1`] = ` 13 | [ 14 | "ModuleBuildError: Module build failed (from \`replaced original path\`): 15 | CoffeeScriptError: Error: Cannot resolve module '@babel/preset-env1' from paths [''] from /node_modules/@babel/core/lib/config/files/plugins.js", 16 | ] 17 | `; 18 | 19 | exports[`loader should throw an error on invalid CoffeeScript options: warnings 1`] = `[]`; 20 | 21 | exports[`loader should work and code without the top-level function safety wrapper: errors 1`] = `[]`; 22 | 23 | exports[`loader should work and code without the top-level function safety wrapper: source 1`] = ` 24 | "var changeNumbers, inner, outer; 25 | 26 | outer = 1; 27 | 28 | changeNumbers = function() { 29 | var inner; 30 | inner = -1; 31 | return outer = 10; 32 | }; 33 | 34 | inner = changeNumbers(); 35 | " 36 | `; 37 | 38 | exports[`loader should work and code without the top-level function safety wrapper: sourceMap 1`] = `undefined`; 39 | 40 | exports[`loader should work and code without the top-level function safety wrapper: warnings 1`] = `[]`; 41 | 42 | exports[`loader should work and generate source maps (take value from the \`compiler.devtool\` option): errors 1`] = `[]`; 43 | 44 | exports[`loader should work and generate source maps (take value from the \`compiler.devtool\` option): source 1`] = ` 45 | "var cubes, list, math, num, number, opposite, race, square; 46 | 47 | import * as local from './local-file.coffee'; 48 | 49 | number = 42; 50 | 51 | opposite = true; 52 | 53 | if (opposite) { 54 | // Conditions: 55 | number = -42; 56 | } 57 | 58 | // Functions: 59 | square = function(x) { 60 | return x * x; 61 | }; 62 | 63 | // Arrays: 64 | list = [1, 2, 3, 4, 5]; 65 | 66 | // Objects: 67 | math = { 68 | root: Math.sqrt, 69 | square: square, 70 | cube: function(x) { 71 | return x * square(x); 72 | } 73 | }; 74 | 75 | // Splats: 76 | race = function(winner, ...runners) { 77 | return print(winner, runners); 78 | }; 79 | 80 | if (typeof elvis !== "undefined" && elvis !== null) { 81 | // Existence: 82 | alert("I knew it!"); 83 | } 84 | 85 | // Array comprehensions: 86 | cubes = (function() { 87 | var i, len, results; 88 | results = []; 89 | for (i = 0, len = list.length; i < len; i++) { 90 | num = list[i]; 91 | results.push(math.cube(num)); 92 | } 93 | return results; 94 | })(); 95 | 96 | export default {number, opposite, square, list, math, race, cubes, local}; 97 | " 98 | `; 99 | 100 | exports[`loader should work and generate source maps (take value from the \`compiler.devtool\` option): sourceMap 1`] = ` 101 | { 102 | "mappings": "AAAA,IAAA,KAAA,EAAA,IAAA,EAAA,IAAA,EAAA,GAAA,EAAA,MAAA,EAAA,QAAA,EAAA,IAAA,EAAA;;AAAA,OAAO,CAAA,SAAP,MAAA;;AAGA,MAAA,GAAW;;AACX,QAAA,GAAW;;AAGX,IAAgB,QAAhB;;EAAA,MAAA,GAAS,CAAC,GAAV;CAPA;;;AAUA,MAAA,GAAS,QAAA,CAAC,CAAD,CAAA;SAAO,CAAA,GAAI;AAAX,EAVT;;;AAaA,IAAA,GAAO,CAAC,CAAD,EAAI,CAAJ,EAAO,CAAP,EAAU,CAAV,EAAa,CAAb,EAbP;;;AAgBA,IAAA,GACE;EAAA,IAAA,EAAQ,IAAI,CAAC,IAAb;EACA,MAAA,EAAQ,MADR;EAEA,IAAA,EAAQ,QAAA,CAAC,CAAD,CAAA;WAAO,CAAA,GAAI,MAAA,CAAO,CAAP;EAAX;AAFR,EAjBF;;;AAsBA,IAAA,GAAO,QAAA,CAAC,MAAD,EAAA,GAAS,OAAT,CAAA;SACL,KAAA,CAAM,MAAN,EAAc,OAAd;AADK;;AAIP,IAAsB,8CAAtB;;EAAA,KAAA,CAAM,YAAN,EAAA;CA1BA;;;AA6BA,KAAA;;AAAS;EAAA,KAAA,sCAAA;;iBAAA,IAAI,CAAC,IAAL,CAAU,GAAV;EAAA,CAAA;;;;AAET,OAAA,QAAe,CAAE,MAAF,EAAU,QAAV,EAAoB,MAApB,EAA4B,IAA5B,EAAkC,IAAlC,EAAwC,IAAxC,EAA8C,KAA9C,EAAqD,KAArD", 103 | "names": [], 104 | "sourceRoot": "", 105 | "sources": [ 106 | "/absolute/path/to/test/fixtures/foo.coffee", 107 | ], 108 | "sourcesContent": [ 109 | "import * as local from './local-file.coffee'; 110 | 111 | # Assignment: 112 | number = 42 113 | opposite = true 114 | 115 | # Conditions: 116 | number = -42 if opposite 117 | 118 | # Functions: 119 | square = (x) -> x * x 120 | 121 | # Arrays: 122 | list = [1, 2, 3, 4, 5] 123 | 124 | # Objects: 125 | math = 126 | root: Math.sqrt 127 | square: square 128 | cube: (x) -> x * square x 129 | 130 | # Splats: 131 | race = (winner, runners...) -> 132 | print winner, runners 133 | 134 | # Existence: 135 | alert "I knew it!" if elvis? 136 | 137 | # Array comprehensions: 138 | cubes = (math.cube num for num in list) 139 | 140 | export default { number, opposite, square, list, math, race, cubes, local } 141 | ", 142 | ], 143 | "version": 3, 144 | } 145 | `; 146 | 147 | exports[`loader should work and generate source maps (take value from the \`compiler.devtool\` option): warnings 1`] = `[]`; 148 | 149 | exports[`loader should work and generate source maps (take value from the \`sourceMap\` option): errors 1`] = `[]`; 150 | 151 | exports[`loader should work and generate source maps (take value from the \`sourceMap\` option): source 1`] = ` 152 | "var cubes, list, math, num, number, opposite, race, square; 153 | 154 | import * as local from './local-file.coffee'; 155 | 156 | number = 42; 157 | 158 | opposite = true; 159 | 160 | if (opposite) { 161 | // Conditions: 162 | number = -42; 163 | } 164 | 165 | // Functions: 166 | square = function(x) { 167 | return x * x; 168 | }; 169 | 170 | // Arrays: 171 | list = [1, 2, 3, 4, 5]; 172 | 173 | // Objects: 174 | math = { 175 | root: Math.sqrt, 176 | square: square, 177 | cube: function(x) { 178 | return x * square(x); 179 | } 180 | }; 181 | 182 | // Splats: 183 | race = function(winner, ...runners) { 184 | return print(winner, runners); 185 | }; 186 | 187 | if (typeof elvis !== "undefined" && elvis !== null) { 188 | // Existence: 189 | alert("I knew it!"); 190 | } 191 | 192 | // Array comprehensions: 193 | cubes = (function() { 194 | var i, len, results; 195 | results = []; 196 | for (i = 0, len = list.length; i < len; i++) { 197 | num = list[i]; 198 | results.push(math.cube(num)); 199 | } 200 | return results; 201 | })(); 202 | 203 | export default {number, opposite, square, list, math, race, cubes, local}; 204 | " 205 | `; 206 | 207 | exports[`loader should work and generate source maps (take value from the \`sourceMap\` option): sourceMap 1`] = ` 208 | { 209 | "mappings": "AAAA,IAAA,KAAA,EAAA,IAAA,EAAA,IAAA,EAAA,GAAA,EAAA,MAAA,EAAA,QAAA,EAAA,IAAA,EAAA;;AAAA,OAAO,CAAA,SAAP,MAAA;;AAGA,MAAA,GAAW;;AACX,QAAA,GAAW;;AAGX,IAAgB,QAAhB;;EAAA,MAAA,GAAS,CAAC,GAAV;CAPA;;;AAUA,MAAA,GAAS,QAAA,CAAC,CAAD,CAAA;SAAO,CAAA,GAAI;AAAX,EAVT;;;AAaA,IAAA,GAAO,CAAC,CAAD,EAAI,CAAJ,EAAO,CAAP,EAAU,CAAV,EAAa,CAAb,EAbP;;;AAgBA,IAAA,GACE;EAAA,IAAA,EAAQ,IAAI,CAAC,IAAb;EACA,MAAA,EAAQ,MADR;EAEA,IAAA,EAAQ,QAAA,CAAC,CAAD,CAAA;WAAO,CAAA,GAAI,MAAA,CAAO,CAAP;EAAX;AAFR,EAjBF;;;AAsBA,IAAA,GAAO,QAAA,CAAC,MAAD,EAAA,GAAS,OAAT,CAAA;SACL,KAAA,CAAM,MAAN,EAAc,OAAd;AADK;;AAIP,IAAsB,8CAAtB;;EAAA,KAAA,CAAM,YAAN,EAAA;CA1BA;;;AA6BA,KAAA;;AAAS;EAAA,KAAA,sCAAA;;iBAAA,IAAI,CAAC,IAAL,CAAU,GAAV;EAAA,CAAA;;;;AAET,OAAA,QAAe,CAAE,MAAF,EAAU,QAAV,EAAoB,MAApB,EAA4B,IAA5B,EAAkC,IAAlC,EAAwC,IAAxC,EAA8C,KAA9C,EAAqD,KAArD", 210 | "names": [], 211 | "sourceRoot": "", 212 | "sources": [ 213 | "/absolute/path/to/test/fixtures/foo.coffee", 214 | ], 215 | "sourcesContent": [ 216 | "import * as local from './local-file.coffee'; 217 | 218 | # Assignment: 219 | number = 42 220 | opposite = true 221 | 222 | # Conditions: 223 | number = -42 if opposite 224 | 225 | # Functions: 226 | square = (x) -> x * x 227 | 228 | # Arrays: 229 | list = [1, 2, 3, 4, 5] 230 | 231 | # Objects: 232 | math = 233 | root: Math.sqrt 234 | square: square 235 | cube: (x) -> x * square x 236 | 237 | # Splats: 238 | race = (winner, runners...) -> 239 | print winner, runners 240 | 241 | # Existence: 242 | alert "I knew it!" if elvis? 243 | 244 | # Array comprehensions: 245 | cubes = (math.cube num for num in list) 246 | 247 | export default { number, opposite, square, list, math, race, cubes, local } 248 | ", 249 | ], 250 | "version": 3, 251 | } 252 | `; 253 | 254 | exports[`loader should work and generate source maps (take value from the \`sourceMap\` option): warnings 1`] = `[]`; 255 | 256 | exports[`loader should work and generate source maps (the \`sourceMap\` option prefer over the \`compiler.devtool\` option): errors 1`] = `[]`; 257 | 258 | exports[`loader should work and generate source maps (the \`sourceMap\` option prefer over the \`compiler.devtool\` option): source 1`] = ` 259 | "var cubes, list, math, num, number, opposite, race, square; 260 | 261 | import * as local from './local-file.coffee'; 262 | 263 | number = 42; 264 | 265 | opposite = true; 266 | 267 | if (opposite) { 268 | // Conditions: 269 | number = -42; 270 | } 271 | 272 | // Functions: 273 | square = function(x) { 274 | return x * x; 275 | }; 276 | 277 | // Arrays: 278 | list = [1, 2, 3, 4, 5]; 279 | 280 | // Objects: 281 | math = { 282 | root: Math.sqrt, 283 | square: square, 284 | cube: function(x) { 285 | return x * square(x); 286 | } 287 | }; 288 | 289 | // Splats: 290 | race = function(winner, ...runners) { 291 | return print(winner, runners); 292 | }; 293 | 294 | if (typeof elvis !== "undefined" && elvis !== null) { 295 | // Existence: 296 | alert("I knew it!"); 297 | } 298 | 299 | // Array comprehensions: 300 | cubes = (function() { 301 | var i, len, results; 302 | results = []; 303 | for (i = 0, len = list.length; i < len; i++) { 304 | num = list[i]; 305 | results.push(math.cube(num)); 306 | } 307 | return results; 308 | })(); 309 | 310 | export default {number, opposite, square, list, math, race, cubes, local}; 311 | " 312 | `; 313 | 314 | exports[`loader should work and generate source maps (the \`sourceMap\` option prefer over the \`compiler.devtool\` option): sourceMap 1`] = ` 315 | { 316 | "mappings": "AAAA,IAAA,KAAA,EAAA,IAAA,EAAA,IAAA,EAAA,GAAA,EAAA,MAAA,EAAA,QAAA,EAAA,IAAA,EAAA;;AAAA,OAAO,CAAA,SAAP,MAAA;;AAGA,MAAA,GAAW;;AACX,QAAA,GAAW;;AAGX,IAAgB,QAAhB;;EAAA,MAAA,GAAS,CAAC,GAAV;CAPA;;;AAUA,MAAA,GAAS,QAAA,CAAC,CAAD,CAAA;SAAO,CAAA,GAAI;AAAX,EAVT;;;AAaA,IAAA,GAAO,CAAC,CAAD,EAAI,CAAJ,EAAO,CAAP,EAAU,CAAV,EAAa,CAAb,EAbP;;;AAgBA,IAAA,GACE;EAAA,IAAA,EAAQ,IAAI,CAAC,IAAb;EACA,MAAA,EAAQ,MADR;EAEA,IAAA,EAAQ,QAAA,CAAC,CAAD,CAAA;WAAO,CAAA,GAAI,MAAA,CAAO,CAAP;EAAX;AAFR,EAjBF;;;AAsBA,IAAA,GAAO,QAAA,CAAC,MAAD,EAAA,GAAS,OAAT,CAAA;SACL,KAAA,CAAM,MAAN,EAAc,OAAd;AADK;;AAIP,IAAsB,8CAAtB;;EAAA,KAAA,CAAM,YAAN,EAAA;CA1BA;;;AA6BA,KAAA;;AAAS;EAAA,KAAA,sCAAA;;iBAAA,IAAI,CAAC,IAAL,CAAU,GAAV;EAAA,CAAA;;;;AAET,OAAA,QAAe,CAAE,MAAF,EAAU,QAAV,EAAoB,MAApB,EAA4B,IAA5B,EAAkC,IAAlC,EAAwC,IAAxC,EAA8C,KAA9C,EAAqD,KAArD", 317 | "names": [], 318 | "sourceRoot": "", 319 | "sources": [ 320 | "/absolute/path/to/test/fixtures/foo.coffee", 321 | ], 322 | "sourcesContent": [ 323 | "import * as local from './local-file.coffee'; 324 | 325 | # Assignment: 326 | number = 42 327 | opposite = true 328 | 329 | # Conditions: 330 | number = -42 if opposite 331 | 332 | # Functions: 333 | square = (x) -> x * x 334 | 335 | # Arrays: 336 | list = [1, 2, 3, 4, 5] 337 | 338 | # Objects: 339 | math = 340 | root: Math.sqrt 341 | square: square 342 | cube: (x) -> x * square x 343 | 344 | # Splats: 345 | race = (winner, runners...) -> 346 | print winner, runners 347 | 348 | # Existence: 349 | alert "I knew it!" if elvis? 350 | 351 | # Array comprehensions: 352 | cubes = (math.cube num for num in list) 353 | 354 | export default { number, opposite, square, list, math, race, cubes, local } 355 | ", 356 | ], 357 | "version": 3, 358 | } 359 | `; 360 | 361 | exports[`loader should work and generate source maps (the \`sourceMap\` option prefer over the \`compiler.devtool\` option): warnings 1`] = `[]`; 362 | 363 | exports[`loader should work and ignore unknown CoffeeScript options: errors 1`] = `[]`; 364 | 365 | exports[`loader should work and ignore unknown CoffeeScript options: source 1`] = ` 366 | "var cubes, list, math, num, number, opposite, race, square; 367 | 368 | import * as local from './local-file.coffee'; 369 | 370 | number = 42; 371 | 372 | opposite = true; 373 | 374 | if (opposite) { 375 | // Conditions: 376 | number = -42; 377 | } 378 | 379 | // Functions: 380 | square = function(x) { 381 | return x * x; 382 | }; 383 | 384 | // Arrays: 385 | list = [1, 2, 3, 4, 5]; 386 | 387 | // Objects: 388 | math = { 389 | root: Math.sqrt, 390 | square: square, 391 | cube: function(x) { 392 | return x * square(x); 393 | } 394 | }; 395 | 396 | // Splats: 397 | race = function(winner, ...runners) { 398 | return print(winner, runners); 399 | }; 400 | 401 | if (typeof elvis !== "undefined" && elvis !== null) { 402 | // Existence: 403 | alert("I knew it!"); 404 | } 405 | 406 | // Array comprehensions: 407 | cubes = (function() { 408 | var i, len, results; 409 | results = []; 410 | for (i = 0, len = list.length; i < len; i++) { 411 | num = list[i]; 412 | results.push(math.cube(num)); 413 | } 414 | return results; 415 | })(); 416 | 417 | export default {number, opposite, square, list, math, race, cubes, local}; 418 | " 419 | `; 420 | 421 | exports[`loader should work and ignore unknown CoffeeScript options: sourceMap 1`] = `undefined`; 422 | 423 | exports[`loader should work and ignore unknown CoffeeScript options: warnings 1`] = `[]`; 424 | 425 | exports[`loader should work and not generate source maps (take value from the \`compiler.devtool\` option): errors 1`] = `[]`; 426 | 427 | exports[`loader should work and not generate source maps (take value from the \`compiler.devtool\` option): source 1`] = ` 428 | "var cubes, list, math, num, number, opposite, race, square; 429 | 430 | import * as local from './local-file.coffee'; 431 | 432 | number = 42; 433 | 434 | opposite = true; 435 | 436 | if (opposite) { 437 | // Conditions: 438 | number = -42; 439 | } 440 | 441 | // Functions: 442 | square = function(x) { 443 | return x * x; 444 | }; 445 | 446 | // Arrays: 447 | list = [1, 2, 3, 4, 5]; 448 | 449 | // Objects: 450 | math = { 451 | root: Math.sqrt, 452 | square: square, 453 | cube: function(x) { 454 | return x * square(x); 455 | } 456 | }; 457 | 458 | // Splats: 459 | race = function(winner, ...runners) { 460 | return print(winner, runners); 461 | }; 462 | 463 | if (typeof elvis !== "undefined" && elvis !== null) { 464 | // Existence: 465 | alert("I knew it!"); 466 | } 467 | 468 | // Array comprehensions: 469 | cubes = (function() { 470 | var i, len, results; 471 | results = []; 472 | for (i = 0, len = list.length; i < len; i++) { 473 | num = list[i]; 474 | results.push(math.cube(num)); 475 | } 476 | return results; 477 | })(); 478 | 479 | export default {number, opposite, square, list, math, race, cubes, local}; 480 | " 481 | `; 482 | 483 | exports[`loader should work and not generate source maps (take value from the \`compiler.devtool\` option): sourceMap 1`] = `undefined`; 484 | 485 | exports[`loader should work and not generate source maps (take value from the \`compiler.devtool\` option): warnings 1`] = `[]`; 486 | 487 | exports[`loader should work and not generate source maps (take value from the \`sourceMap\` option): errors 1`] = `[]`; 488 | 489 | exports[`loader should work and not generate source maps (take value from the \`sourceMap\` option): source 1`] = ` 490 | "var cubes, list, math, num, number, opposite, race, square; 491 | 492 | import * as local from './local-file.coffee'; 493 | 494 | number = 42; 495 | 496 | opposite = true; 497 | 498 | if (opposite) { 499 | // Conditions: 500 | number = -42; 501 | } 502 | 503 | // Functions: 504 | square = function(x) { 505 | return x * x; 506 | }; 507 | 508 | // Arrays: 509 | list = [1, 2, 3, 4, 5]; 510 | 511 | // Objects: 512 | math = { 513 | root: Math.sqrt, 514 | square: square, 515 | cube: function(x) { 516 | return x * square(x); 517 | } 518 | }; 519 | 520 | // Splats: 521 | race = function(winner, ...runners) { 522 | return print(winner, runners); 523 | }; 524 | 525 | if (typeof elvis !== "undefined" && elvis !== null) { 526 | // Existence: 527 | alert("I knew it!"); 528 | } 529 | 530 | // Array comprehensions: 531 | cubes = (function() { 532 | var i, len, results; 533 | results = []; 534 | for (i = 0, len = list.length; i < len; i++) { 535 | num = list[i]; 536 | results.push(math.cube(num)); 537 | } 538 | return results; 539 | })(); 540 | 541 | export default {number, opposite, square, list, math, race, cubes, local}; 542 | " 543 | `; 544 | 545 | exports[`loader should work and not generate source maps (take value from the \`sourceMap\` option): sourceMap 1`] = `undefined`; 546 | 547 | exports[`loader should work and not generate source maps (take value from the \`sourceMap\` option): warnings 1`] = `[]`; 548 | 549 | exports[`loader should work and support CoffeeScript options: errors 1`] = `[]`; 550 | 551 | exports[`loader should work and support CoffeeScript options: source 1`] = ` 552 | ""use strict"; 553 | 554 | function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } 555 | Object.defineProperty(exports, "__esModule", { 556 | value: true 557 | }); 558 | exports["default"] = void 0; 559 | var local = _interopRequireWildcard(require("./local-file.coffee")); 560 | function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, "default": e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); } 561 | var cubes, list, math, num, number, opposite, race, square; 562 | number = 42; 563 | opposite = true; 564 | if (opposite) { 565 | // Conditions: 566 | number = -42; 567 | } 568 | 569 | // Functions: 570 | square = function square(x) { 571 | return x * x; 572 | }; 573 | 574 | // Arrays: 575 | list = [1, 2, 3, 4, 5]; 576 | 577 | // Objects: 578 | math = { 579 | root: Math.sqrt, 580 | square: square, 581 | cube: function cube(x) { 582 | return x * square(x); 583 | } 584 | }; 585 | 586 | // Splats: 587 | race = function race(winner) { 588 | for (var _len = arguments.length, runners = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { 589 | runners[_key - 1] = arguments[_key]; 590 | } 591 | return print(winner, runners); 592 | }; 593 | if (typeof elvis !== "undefined" && elvis !== null) { 594 | // Existence: 595 | alert("I knew it!"); 596 | } 597 | 598 | // Array comprehensions: 599 | cubes = function () { 600 | var i, len, results; 601 | results = []; 602 | for (i = 0, len = list.length; i < len; i++) { 603 | num = list[i]; 604 | results.push(math.cube(num)); 605 | } 606 | return results; 607 | }(); 608 | var _default = exports["default"] = { 609 | number: number, 610 | opposite: opposite, 611 | square: square, 612 | list: list, 613 | math: math, 614 | race: race, 615 | cubes: cubes, 616 | local: local 617 | };" 618 | `; 619 | 620 | exports[`loader should work and support CoffeeScript options: sourceMap 1`] = `undefined`; 621 | 622 | exports[`loader should work and support CoffeeScript options: warnings 1`] = `[]`; 623 | 624 | exports[`loader should work for Literate CoffeeScript: errors 1`] = `[]`; 625 | 626 | exports[`loader should work for Literate CoffeeScript: source 1`] = ` 627 | " // The **Scope** class regulates lexical scoping within CoffeeScript. As you 628 | // generate code, you create a tree of scopes in the same shape as the nested 629 | // function bodies. Each scope knows about the variables declared within it, 630 | // and has a reference to its parent enclosing scope. In this way, we know which 631 | // variables are new and need to be declared with \`var\`, and which are shared 632 | // with external scopes. 633 | var Scope, 634 | indexOf = [].indexOf; 635 | 636 | exports.Scope = Scope = class Scope { 637 | // Initialize a scope with its parent, for lookups up the chain, 638 | // as well as a reference to the **Block** node it belongs to, which is 639 | // where it should declare its variables, a reference to the function that 640 | // it belongs to, and a list of variables referenced in the source code 641 | // and therefore should be avoided when generating variables. Also track comments 642 | // that should be output as part of variable declarations. 643 | constructor(parent, expressions, method, referencedVars) { 644 | var ref, ref1; 645 | this.parent = parent; 646 | this.expressions = expressions; 647 | this.method = method; 648 | this.referencedVars = referencedVars; 649 | this.variables = [ 650 | { 651 | name: 'arguments', 652 | type: 'arguments' 653 | } 654 | ]; 655 | this.comments = {}; 656 | this.positions = {}; 657 | if (!this.parent) { 658 | this.utilities = {}; 659 | } 660 | // The \`@root\` is the top-level **Scope** object for a given file. 661 | this.root = (ref = (ref1 = this.parent) != null ? ref1.root : void 0) != null ? ref : this; 662 | } 663 | 664 | // Adds a new variable or overrides an existing one. 665 | add(name, type, immediate) { 666 | if (this.shared && !immediate) { 667 | return this.parent.add(name, type, immediate); 668 | } 669 | if (Object.prototype.hasOwnProperty.call(this.positions, name)) { 670 | return this.variables[this.positions[name]].type = type; 671 | } else { 672 | return this.positions[name] = this.variables.push({name, type}) - 1; 673 | } 674 | } 675 | 676 | // When \`super\` is called, we need to find the name of the current method we're 677 | // in, so that we know how to invoke the same method of the parent class. This 678 | // can get complicated if super is being called from an inner function. 679 | // \`namedMethod\` will walk up the scope tree until it either finds the first 680 | // function object that has a name filled in, or bottoms out. 681 | namedMethod() { 682 | var ref; 683 | if (((ref = this.method) != null ? ref.name : void 0) || !this.parent) { 684 | return this.method; 685 | } 686 | return this.parent.namedMethod(); 687 | } 688 | 689 | // Look up a variable name in lexical scope, and declare it if it does not 690 | // already exist. 691 | find(name, type = 'var') { 692 | if (this.check(name)) { 693 | return true; 694 | } 695 | this.add(name, type); 696 | return false; 697 | } 698 | 699 | // Reserve a variable name as originating from a function parameter for this 700 | // scope. No \`var\` required for internal references. 701 | parameter(name) { 702 | if (this.shared && this.parent.check(name, true)) { 703 | return; 704 | } 705 | return this.add(name, 'param'); 706 | } 707 | 708 | // Just check to see if a variable has already been declared, without reserving, 709 | // walks up to the root scope. 710 | check(name) { 711 | var ref; 712 | return !!(this.type(name) || ((ref = this.parent) != null ? ref.check(name) : void 0)); 713 | } 714 | 715 | // Generate a temporary variable name at the given index. 716 | temporary(name, index, single = false) { 717 | var diff, endCode, letter, newCode, num, startCode; 718 | if (single) { 719 | startCode = name.charCodeAt(0); 720 | endCode = 'z'.charCodeAt(0); 721 | diff = endCode - startCode; 722 | newCode = startCode + index % (diff + 1); 723 | letter = String.fromCharCode(newCode); 724 | num = Math.floor(index / (diff + 1)); 725 | return \`\${letter}\${num || ''}\`; 726 | } else { 727 | return \`\${name}\${index || ''}\`; 728 | } 729 | } 730 | 731 | // Gets the type of a variable. 732 | type(name) { 733 | var i, len, ref, v; 734 | ref = this.variables; 735 | for (i = 0, len = ref.length; i < len; i++) { 736 | v = ref[i]; 737 | if (v.name === name) { 738 | return v.type; 739 | } 740 | } 741 | return null; 742 | } 743 | 744 | // If we need to store an intermediate result, find an available name for a 745 | // compiler-generated variable. \`_var\`, \`_var2\`, and so on... 746 | freeVariable(name, options = {}) { 747 | var index, ref, temp; 748 | index = 0; 749 | while (true) { 750 | temp = this.temporary(name, index, options.single); 751 | if (!(this.check(temp) || indexOf.call(this.root.referencedVars, temp) >= 0)) { 752 | break; 753 | } 754 | index++; 755 | } 756 | if ((ref = options.reserve) != null ? ref : true) { 757 | this.add(temp, 'var', true); 758 | } 759 | return temp; 760 | } 761 | 762 | // Ensure that an assignment is made at the top of this scope 763 | // (or at the top-level scope, if requested). 764 | assign(name, value) { 765 | this.add(name, { 766 | value, 767 | assigned: true 768 | }, true); 769 | return this.hasAssignments = true; 770 | } 771 | 772 | // Does this scope have any declared variables? 773 | hasDeclarations() { 774 | return !!this.declaredVariables().length; 775 | } 776 | 777 | // Return the list of variables first declared in this scope. 778 | declaredVariables() { 779 | var v; 780 | return ((function() { 781 | var i, len, ref, results; 782 | ref = this.variables; 783 | results = []; 784 | for (i = 0, len = ref.length; i < len; i++) { 785 | v = ref[i]; 786 | if (v.type === 'var') { 787 | results.push(v.name); 788 | } 789 | } 790 | return results; 791 | }).call(this)).sort(); 792 | } 793 | 794 | // Return the list of assignments that are supposed to be made at the top 795 | // of this scope. 796 | assignedVariables() { 797 | var i, len, ref, results, v; 798 | ref = this.variables; 799 | results = []; 800 | for (i = 0, len = ref.length; i < len; i++) { 801 | v = ref[i]; 802 | if (v.type.assigned) { 803 | results.push(\`\${v.name} = \${v.type.value}\`); 804 | } 805 | } 806 | return results; 807 | } 808 | 809 | }; 810 | " 811 | `; 812 | 813 | exports[`loader should work for Literate CoffeeScript: sourceMap 1`] = `undefined`; 814 | 815 | exports[`loader should work for Literate CoffeeScript: warnings 1`] = `[]`; 816 | 817 | exports[`loader should work: errors 1`] = `[]`; 818 | 819 | exports[`loader should work: source 1`] = ` 820 | "var cubes, list, math, num, number, opposite, race, square; 821 | 822 | import * as local from './local-file.coffee'; 823 | 824 | number = 42; 825 | 826 | opposite = true; 827 | 828 | if (opposite) { 829 | // Conditions: 830 | number = -42; 831 | } 832 | 833 | // Functions: 834 | square = function(x) { 835 | return x * x; 836 | }; 837 | 838 | // Arrays: 839 | list = [1, 2, 3, 4, 5]; 840 | 841 | // Objects: 842 | math = { 843 | root: Math.sqrt, 844 | square: square, 845 | cube: function(x) { 846 | return x * square(x); 847 | } 848 | }; 849 | 850 | // Splats: 851 | race = function(winner, ...runners) { 852 | return print(winner, runners); 853 | }; 854 | 855 | if (typeof elvis !== "undefined" && elvis !== null) { 856 | // Existence: 857 | alert("I knew it!"); 858 | } 859 | 860 | // Array comprehensions: 861 | cubes = (function() { 862 | var i, len, results; 863 | results = []; 864 | for (i = 0, len = list.length; i < len; i++) { 865 | num = list[i]; 866 | results.push(math.cube(num)); 867 | } 868 | return results; 869 | })(); 870 | 871 | export default {number, opposite, square, list, math, race, cubes, local}; 872 | " 873 | `; 874 | 875 | exports[`loader should work: sourceMap 1`] = `undefined`; 876 | 877 | exports[`loader should work: warnings 1`] = `[]`; 878 | --------------------------------------------------------------------------------