Repository: rollup/rollup-plugin-replace Branch: master Commit: befd72385ef9 Files: 39 Total size: 18.4 KB Directory structure: gitextract_lomxykll/ ├── .eslintrc ├── .gitignore ├── .huskyrc ├── .lintstagedrc ├── .prettierrc ├── .travis.yml ├── CHANGELOG.md ├── README.md ├── appveyor.yml ├── index.d.ts ├── package.json ├── rollup.config.js ├── src/ │ └── index.js ├── test/ │ ├── form/ │ │ ├── delimiters/ │ │ │ ├── _config.js │ │ │ ├── input.js │ │ │ └── output.js │ │ ├── match-variables/ │ │ │ ├── _config.js │ │ │ ├── input.js │ │ │ └── output.js │ │ ├── observe-plugin-options/ │ │ │ ├── _config.js │ │ │ ├── input.js │ │ │ └── output.js │ │ ├── replace-strings/ │ │ │ ├── _config.js │ │ │ ├── input.js │ │ │ └── output.js │ │ ├── replacement-function/ │ │ │ ├── _config.js │ │ │ ├── input.js │ │ │ └── output.js │ │ └── special-characters/ │ │ ├── _config.js │ │ ├── input.js │ │ └── output.js │ ├── function/ │ │ ├── replacement-function/ │ │ │ ├── _config.js │ │ │ ├── dir/ │ │ │ │ └── foo.js │ │ │ └── main.js │ │ └── word-boundaries/ │ │ ├── _config.js │ │ └── main.js │ └── test.js ├── tsconfig.json └── typings-test.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .eslintrc ================================================ { "root": true, "rules": { "indent": [ 2, "tab", { "SwitchCase": 1 } ], "semi": [ 2, "always" ], "keyword-spacing": [ 2, { "before": true, "after": true } ], "space-before-blocks": [ 2, "always" ], "no-mixed-spaces-and-tabs": [ 2, "smart-tabs" ], "no-cond-assign": 0, "no-unused-vars": 2, "object-shorthand": [ 2, "always" ], "no-const-assign": 2, "no-class-assign": 2, "no-this-before-super": 2, "no-var": 2, "no-unreachable": 2, "valid-typeof": 2, "quote-props": [ 2, "as-needed" ], "one-var": [ 2, "never" ], "prefer-arrow-callback": 2, "prefer-const": [ 2, { "destructuring": "all" } ], "arrow-spacing": 2 }, "env": { "es6": true, "browser": true, "node": true }, "extends": [ "eslint:recommended", "plugin:import/errors", "plugin:import/warnings" ], "parserOptions": { "ecmaVersion": 8, "sourceType": "module" }, "settings": { "import/ignore": [ 0, [ "\\.path.js$" ] ] } } ================================================ FILE: .gitignore ================================================ .DS_Store node_modules dist .gobble* ================================================ FILE: .huskyrc ================================================ { "hooks": { "post-commit": "git reset", "pre-commit": "lint-staged" } } ================================================ FILE: .lintstagedrc ================================================ { "{src/**/*,test/test,test/**/_config}.js": [ "prettier --write", "eslint --fix", "git add" ] } ================================================ FILE: .prettierrc ================================================ { "singleQuote": true, "useTabs": true, "printWidth": 100 } ================================================ FILE: .travis.yml ================================================ sudo: false language: node_js node_js: - "8" - "10" env: global: - BUILD_TIMEOUT=10000 install: npm ci ================================================ FILE: CHANGELOG.md ================================================ # rollup-plugin-replace changelog ## 2.2.0 *2019-04-10* * Add index.d.ts typings file ([#31](https://github.com/rollup/rollup-plugin-replace/pull/31)) ## 2.1.1 *2019-03-18* * Update rollup-pluginutils ([#29](https://github.com/rollup/rollup-plugin-replace/pull/29)) * Update dependencies ([#30](https://github.com/rollup/rollup-plugin-replace/pull/30)) ## 2.1.0 *2018-10-07* * Do not mutate values passed as option ([#22](https://github.com/rollup/rollup-plugin-replace/pull/22)) * Update dependencies and improve tests ([#26](https://github.com/rollup/rollup-plugin-replace/pull/26)) ## 2.0.0 * Only match on word boundaries, unless delimiters are empty strings ([#10](https://github.com/rollup/rollup-plugin-replace/pull/10)) ## 1.2.1 * Match longest keys first ([#8](https://github.com/rollup/rollup-plugin-replace/pull/8)) * Escape keys ([#9](https://github.com/rollup/rollup-plugin-replace/pull/9)) ## 1.2.0 * Allow replacement to be a function that takes a module ID ([#1](https://github.com/rollup/rollup-plugin-replace/issues/1)) ## 1.1.1 * Return a `name` ## 1.1.0 * Generate sourcemaps by default ## 1.0.1 * Include correct files in package ## 1.0.0 * First release ================================================ FILE: README.md ================================================ # Moved This module has moved and is now available at [@rollup/plugin-replace](https://github.com/rollup/plugins). Please update your dependencies. This repository is no longer maintained. # rollup-plugin-replace [![](https://img.shields.io/npm/v/rollup-plugin-replace.svg?style=flat)](https://www.npmjs.com/package/rollup-plugin-replace) Replace strings in files while bundling them. ## Installation ```bash npm install --save-dev rollup-plugin-replace ``` ## Usage Generally, you need to ensure that rollup-plugin-replace goes _before_ other things (like rollup-plugin-commonjs) in your `plugins` array, so that those plugins can apply any optimisations such as dead code removal. ```js // rollup.config.js import replace from 'rollup-plugin-replace'; export default { // ... plugins: [ replace({ ENVIRONMENT: JSON.stringify('production') }) ] }; ``` ## Options ```js { // a minimatch pattern, or array of patterns, of files that // should be processed by this plugin (if omitted, all files // are included by default)... include: 'config.js', // ...and those that shouldn't, if `include` is otherwise // too permissive exclude: 'node_modules/**', // To replace every occurrence of `<@foo@>` instead of every // occurrence of `foo`, supply delimiters delimiters: ['<@', '@>'], // All other options are treated as `string: replacement` // replacers... VERSION: '1.0.0', ENVIRONMENT: JSON.stringify('development'), // or `string: (id) => replacement` functions... __dirname: (id) => `'${path.dirname(id)}'`, // ...unless you want to be careful about separating // values from other options, in which case you can: values: { VERSION: '1.0.0', ENVIRONMENT: JSON.stringify('development') } } ``` ## Word boundaries By default, values will only match if they are surrounded by _word boundaries_ — i.e. with options like this... ```js { changed: 'replaced'; } ``` ...and code like this... ```js console.log('changed'); console.log('unchanged'); ``` ...the result will be this: ```js console.log('replaced'); console.log('unchanged'); ``` If that's not what you want, specify empty strings as delimiters: ```js { changed: 'replaced', delimiters: ['', ''] } ``` ## License MIT ================================================ FILE: appveyor.yml ================================================ # http://www.appveyor.com/docs/appveyor-yml version: "{build}" clone_depth: 10 init: - git config --global core.autocrlf false environment: matrix: # node.js - nodejs_version: stable install: - ps: Install-Product node $env:nodejs_version - npm ci build: off test_script: - node --version && npm --version - npm test matrix: fast_finish: false # cache: # - C:\Users\appveyor\AppData\Roaming\npm-cache -> package.json # npm cache # - node_modules -> package.json # local npm modules ================================================ FILE: index.d.ts ================================================ import { Plugin } from 'rollup'; type Replacement = string | ((id: string) => string); interface RollupReplaceOptions { /** * A minimatch pattern, or array of patterns, of files that should be * processed by this plugin (if omitted, all files are included by default) */ include?: string | RegExp | ReadonlyArray | null; /** * Files that should be excluded, if `include` is otherwise too permissive. */ exclude?: string | RegExp | ReadonlyArray | null; /** * To replace every occurrence of `<@foo@>` instead of every occurrence * of `foo`, supply delimiters */ delimiters?: [string, string]; /** * You can separate values to replace from other options. */ values?: { [str: string]: Replacement }; /** * All other options are treated as `string: replacement` replacers, * or `string: (id) => replacement` functions. */ [str: string]: Replacement | RollupReplaceOptions['include'] | RollupReplaceOptions['values']; } /** * Replace strings in files while bundling them. */ export default function replace(options?: RollupReplaceOptions): Plugin; ================================================ FILE: package.json ================================================ { "name": "rollup-plugin-replace", "version": "2.2.0", "devDependencies": { "eslint": "^6.3.0", "eslint-plugin-import": "^2.18.2", "husky": "^3.0.5", "lint-staged": "^9.2.5", "locate-character": "^2.0.5", "mocha": "^6.2.0", "prettier": "^1.16.4", "rollup": "^1.9.1", "rollup-plugin-buble": "^0.19.6", "shx": "^0.3.2", "source-map": "^0.7.3", "typescript": "^3.4.3" }, "main": "dist/rollup-plugin-replace.cjs.js", "module": "dist/rollup-plugin-replace.es.js", "dependencies": { "magic-string": "^0.25.2", "rollup-pluginutils": "^2.6.0" }, "scripts": { "test": "npm run test:only", "test:only": "mocha && tsc", "pretest": "npm run build", "build": "rollup -c", "prebuild": "shx rm -rf dist/*", "lint": "prettier --write src/**/*.js test/test.js test/**/_config.js && eslint --fix src/**/*.js test/test.js test/**/_config.js", "prepublishOnly": "npm run lint && npm run test:only", "prepare": "npm run build" }, "files": [ "src", "dist", "index.d.ts", "README.md" ], "repository": "rollup/rollup-plugin-replace", "keywords": [ "rollup", "rollup-plugin", "es2015", "npm", "modules" ], "author": "Rich Harris ", "license": "MIT", "bugs": { "url": "https://github.com/rollup/rollup-plugin-replace/issues" }, "homepage": "https://github.com/rollup/rollup-plugin-replace#readme" } ================================================ FILE: rollup.config.js ================================================ import buble from 'rollup-plugin-buble'; import pkg from './package.json'; var external = Object.keys(pkg.dependencies).concat('path'); export default { input: 'src/index.js', plugins: [ buble() ], external, output: [ { file: pkg.main, format: 'cjs' }, { file: pkg.module, format: 'es' } ] }; ================================================ FILE: src/index.js ================================================ import MagicString from 'magic-string'; import { createFilter } from 'rollup-pluginutils'; function escape(str) { return str.replace(/[-[\]/{}()*+?.\\^$|]/g, '\\$&'); } function ensureFunction(functionOrValue) { if (typeof functionOrValue === 'function') return functionOrValue; return () => functionOrValue; } function longest(a, b) { return b.length - a.length; } function getReplacements(options) { if (options.values) { return Object.assign({}, options.values); } else { const values = Object.assign({}, options); delete values.delimiters; delete values.include; delete values.exclude; delete values.sourcemap; delete values.sourceMap; return values; } } function mapToFunctions(object) { return Object.keys(object).reduce((functions, key) => { functions[key] = ensureFunction(object[key]); return functions; }, {}); } export default function replace(options = {}) { const filter = createFilter(options.include, options.exclude); const { delimiters } = options; const functionValues = mapToFunctions(getReplacements(options)); const keys = Object.keys(functionValues) .sort(longest) .map(escape); const pattern = delimiters ? new RegExp(`${escape(delimiters[0])}(${keys.join('|')})${escape(delimiters[1])}`, 'g') : new RegExp(`\\b(${keys.join('|')})\\b`, 'g'); return { name: 'replace', transform(code, id) { if (!filter(id)) return null; const magicString = new MagicString(code); let hasReplacements = false; let match; let start; let end; let replacement; while ((match = pattern.exec(code))) { hasReplacements = true; start = match.index; end = start + match[0].length; replacement = String(functionValues[match[1]](id)); magicString.overwrite(start, end, replacement); } if (!hasReplacements) return null; const result = { code: magicString.toString() }; if (options.sourceMap !== false && options.sourcemap !== false) result.map = magicString.generateMap({ hires: true }); return result; } }; } ================================================ FILE: test/form/delimiters/_config.js ================================================ module.exports = { description: 'observes delimiters', options: { original: 'replaced', delimiters: ['<%', '%>'] } }; ================================================ FILE: test/form/delimiters/input.js ================================================ console.log(` <%original%> <% original%> <%original %> `); ================================================ FILE: test/form/delimiters/output.js ================================================ console.log(` replaced <% original%> <%original %> `); ================================================ FILE: test/form/match-variables/_config.js ================================================ module.exports = { description: 'matches most specific variables', options: { BUILD: 'beta', BUILD_VERSION: '1.0.0' } }; ================================================ FILE: test/form/match-variables/input.js ================================================ console.log('BUILD version BUILD_VERSION'); ================================================ FILE: test/form/match-variables/output.js ================================================ console.log('beta version 1.0.0'); ================================================ FILE: test/form/observe-plugin-options/_config.js ================================================ module.exports = { description: 'does not replace plugin options', options: { original: 'replaced', delimiters: ['', ''], sourcemap: true, sourceMap: true, include: '**/input.js', exclude: 'node_modules/**' } }; ================================================ FILE: test/form/observe-plugin-options/input.js ================================================ console.log(` original delimiters sourcemap sourceMap include exclude `); ================================================ FILE: test/form/observe-plugin-options/output.js ================================================ console.log(` replaced delimiters sourcemap sourceMap include exclude `); ================================================ FILE: test/form/replace-strings/_config.js ================================================ module.exports = { description: 'replaces strings', options: { ANSWER: '42' } }; ================================================ FILE: test/form/replace-strings/input.js ================================================ console.log(ANSWER); ================================================ FILE: test/form/replace-strings/output.js ================================================ console.log(42); ================================================ FILE: test/form/replacement-function/_config.js ================================================ module.exports = { description: 'allows replacement to be a function', options: { __filename(id) { return JSON.stringify(id.slice(__dirname.length + 1)); } } }; ================================================ FILE: test/form/replacement-function/input.js ================================================ export default __filename; ================================================ FILE: test/form/replacement-function/output.js ================================================ export default "input.js"; ================================================ FILE: test/form/special-characters/_config.js ================================================ module.exports = { description: 'supports special characters', options: { "require('one')": '1', delimiters: ['', ''] } }; ================================================ FILE: test/form/special-characters/input.js ================================================ const one = require('one'); console.log(one); ================================================ FILE: test/form/special-characters/output.js ================================================ const one = 1; console.log(one); ================================================ FILE: test/function/replacement-function/_config.js ================================================ module.exports = { description: 'allows replacement to be a function', pluginOptions: { __filename(id) { return JSON.stringify(id.slice(__dirname.length + 1)); } } }; ================================================ FILE: test/function/replacement-function/dir/foo.js ================================================ export default __filename; ================================================ FILE: test/function/replacement-function/main.js ================================================ import foo from './dir/foo.js'; var bar = __filename; // To work around windows issues assert.equal(foo.slice(0, 3), 'dir'); assert.equal(foo.slice(-6), 'foo.js'); assert.equal(foo.length, 10); assert.equal(bar, 'main.js'); ================================================ FILE: test/function/word-boundaries/_config.js ================================================ const assert = require('assert'); module.exports = { description: 'uses word boundaries if delimiters are unspecified', pluginOptions: { changed: 'replaced' }, exports(exports) { assert.deepEqual(exports, { foo: 'unchanged', bar: 'replaced' }); } }; ================================================ FILE: test/function/word-boundaries/main.js ================================================ export const foo = 'unchanged'; export const bar = 'changed'; ================================================ FILE: test/test.js ================================================ /* eslint-env mocha */ /* eslint-disable no-console */ const assert = require('assert'); const { rollup } = require('rollup'); const replace = require('../dist/rollup-plugin-replace.cjs.js'); const fs = require('fs'); const { SourceMapConsumer } = require('source-map'); const { getLocator } = require('locate-character'); process.chdir(__dirname); function execute(code, context = {}) { let fn; const contextKeys = Object.keys(context); const argNames = contextKeys.concat('module', 'exports', 'assert', code); try { fn = new Function(...argNames); } catch (err) { // syntax error console.log(code); throw err; } const module = { exports: {} }; const argValues = contextKeys.map(key => context[key]).concat(module, module.exports, assert); fn(...argValues); return module.exports; } const getOutputFromGenerated = generated => (generated.output ? generated.output[0] : generated); async function getCodeFromBundle(bundle, customOptions = {}) { const options = Object.assign({ format: 'cjs' }, customOptions); return getOutputFromGenerated(await bundle.generate(options)).code; } describe('rollup-plugin-replace', () => { describe('form', () => { const transformContext = {}; fs.readdirSync('form').forEach(dir => { let config; try { config = require(`./form/${dir}/_config.js`); } catch (err) { config = {}; } (config.solo ? it.only : it)(`${dir}: ${config.description}`, () => { const { transform } = replace(config.options); const input = fs.readFileSync(`form/${dir}/input.js`, 'utf-8'); const expected = fs.readFileSync(`form/${dir}/output.js`, 'utf-8').trim(); return Promise.resolve( transform.call(transformContext, input, `${__dirname}/form/${dir}/input.js`) ).then(transformed => { const actual = (transformed ? transformed.code : input).trim(); assert.equal(actual, expected); }); }); }); }); describe('function', () => { fs.readdirSync('function').forEach(dir => { let config; try { config = require(`./function/${dir}/_config.js`); } catch (err) { config = {}; } (config.solo ? it.only : it)(`${dir}: ${config.description}`, async () => { const options = Object.assign( { input: `function/${dir}/main.js` }, config.options || {}, { plugins: [ ...((config.options && config.options.plugins) || []), replace(config.pluginOptions) ] } ); const bundle = await rollup(options); const code = await getCodeFromBundle(bundle); if (config.show || config.solo) { console.error(code); } const exports = execute(code, config.context); if (config.exports) config.exports(exports); }); }); }); describe('misc', () => { it('does not mutate the values map properties', async () => { const valuesMap = { ANSWER: '42' }; const bundle = await rollup({ input: 'main.js', plugins: [ replace({ values: valuesMap }), { resolveId(id) { return id; }, load(importee) { if (importee === 'main.js') { return 'console.log(ANSWER);'; } } } ] }); const { code } = getOutputFromGenerated(await bundle.generate({ format: 'es' })); assert.equal(code.trim(), 'console.log(42);'); assert.deepEqual(valuesMap, { ANSWER: '42' }); }); it('generates sourcemaps', async () => { const bundle = await rollup({ input: 'main.js', onwarn(warning) { throw new Error(warning.message); }, plugins: [ replace({ values: { ANSWER: '42' } }), { resolveId(id) { return id; }, load(importee) { if (importee === 'main.js') { return 'import value from "other.js";\nconsole.log(value);'; } if (importee === 'other.js') { return 'export default ANSWER;'; } } } ] }); const { code, map } = getOutputFromGenerated( await bundle.generate({ format: 'es', sourcemap: true }) ); await SourceMapConsumer.with(map, null, async smc => { const locator = getLocator(code, { offsetLine: 1 }); let generatedLoc = locator('42'); let loc = smc.originalPositionFor(generatedLoc); // 42 assert.equal(loc.source, 'other.js'); assert.equal(loc.line, 1); assert.equal(loc.column, 15); generatedLoc = locator('log'); loc = smc.originalPositionFor(generatedLoc); // log assert.equal(loc.source, 'main.js'); assert.equal(loc.line, 2); assert.equal(loc.column, 8); }); }); it('does not generate sourcemaps if disabled', async () => { let warned = false; const bundle = await rollup({ input: 'main.js', onwarn(warning) { assert.equal( warning.message, "Sourcemap is likely to be incorrect: a plugin ('replace') was used to transform files, but didn't generate a sourcemap for the transformation. Consult the plugin documentation for help" ); warned = true; }, plugins: [ replace({ values: { ANSWER: '42' }, sourcemap: false }), { resolveId(id) { return id; }, load(importee) { if (importee === 'main.js') { return 'import value from "other.js";\nconsole.log(value);'; } if (importee === 'other.js') { return 'export default ANSWER;'; } } } ] }); assert.ok(!warned); await bundle.generate({ format: 'es', sourcemap: true }); assert.ok(warned); }); }); }); ================================================ FILE: tsconfig.json ================================================ { "compilerOptions": { "lib": [ "es6" ], "noImplicitAny": true, "noImplicitThis": true, "strict": true, "noEmit": true, "allowJs": true }, "files": [ "index.d.ts", "typings-test.js" ] } ================================================ FILE: typings-test.js ================================================ // @ts-check import { dirname } from 'path'; import replace from '.'; /** @type {import("rollup").RollupOptions} */ const config = { input: 'main.js', output: { file: 'bundle.js', format: 'iife' }, plugins: [ replace({ include: 'config.js', exclude: 'node_modules/**', delimiters: ['<@', '@>'], VERSION: '1.0.0', ENVIRONMENT: JSON.stringify('development'), __dirname: id => `'${dirname(id)}'`, values: { VERSION: '1.0.0', ENVIRONMENT: JSON.stringify('development') } }) ] }; export default config;