├── .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 |
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 |
--------------------------------------------------------------------------------