0

requirejs source code:

use code below to delete comment

var commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg;

function commentReplace(match, multi, multiText, singlePrefix) {
    return singlePrefix || '';
}

// for example

var funcName = function(){
    /* comment */
    console.log('comment') // comment
    return 'delete comment'
}

funcName.toString().replace(commentRegExp,commentReplace);

i want to know the reason commentRegExp is

/(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg;

instead of

/(\/\*([\s\S]*?)\*\/| \/\/(.*)$)/mg;

so that we can use

funcName.toString().replace(/(\/\*([\s\S]*?)\*\/| \/\/(.*)$)/mg,'')

instead of

funcName.toString().replace(commentRegExp,commentReplace);

who can tell me the role of ([^:]|^) inside /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg

Raman Sahasi
  • 30,180
  • 9
  • 58
  • 71
kwoktung
  • 572
  • 1
  • 4
  • 12

2 Answers2

2

commentRegExp is not meant to be a general purpose regular expression for stripping comments.

If you are looking to strip comments in general, you should do what Mariano said, and use a JavaScript parser.

Why does RequireJS use this expression?

The understand why the regular expression is the way it is, you need to understand what it is used for. It is used in only one place in require.js:

callback
    .toString()
    .replace(commentRegExp, commentReplace)
    .replace(cjsRequireRegExp, function (match, dep) {
        deps.push(dep);
    });

callback is the callback passed to a define call. For instance the single parameter of this call would be callback in the code above:

define(function (require) {});

The RequireJS code I've quoted has for only goal to provide support for the CommonJS-style of importing modules. It goes over the source of the callback and looks for all instance of require calls that have a single parameter which is a string literal. If you have code written in the CommonJS form:

var foo = require("foo");
var bar = require("bar");
// Do stuff with foo and bar.

exports.q = "something";

you can just wrap it in define:

define(function (require, exports, module) {
  var foo = require("foo");
  var bar = require("bar");
  // Do stuff with foo and bar.

  exports.q = "something";
});

Although the require calls look like they are loading modules synchronously, RequireJS always loads modules asynchronously, so in order to have the require calls to work, RequireJS performs a computation that makes the above equivalent to the following:

define(["require", "exports", "module", "foo", "bar"], function (require, exports, module) {
  var foo = require("foo");
  var bar = require("bar");
  // Do stuff with foo and bar.

  exports.q = "something";
});

The array that appears before the callback is the list of dependencies for the module being defined by define. The modules require, exports and module are special modules that are always defined and provide the values to pass to callbacks that use the CommonJS syntax. Then the modules that appeared in require calls are added to the list of dependencies. This means that all modules that appear in require calls in callback passed to define are loaded before the callback runs. So when var foo = require("foo") executes, RequireJS is not loading the module but just fetching it from its cache of modules.

The regular expression you are looking at is used only for the purpose of doing the computation I just described. It allows cases like these to be detected and properly handled by RequireJS:

require("foo" /* something */);
require(// Something
        "foo");

Mariano has already pointed out that although commentRegExp has a provision to not avoid taking '//:' as a comment, it will mangle things like:

var b = "this is //not a comment matched";

For the purpose it is meant to be used, it does not matter. The cjsRequireRegExp expression that is used after commentRegExp is only looking for require calls. So even if a case like the one above happens, it is without consequence because cjsRequireRegExp won't match it. The reason it does not match :// is so that this works:

require("http://foo.com/something")

What about the following?

require("lib//something")

The regular expression will strip from '//' to the end of the line, true. However, '//' is equivalent to '/' so Just make the module name lib/something.

RequireJS is using regular expressions rather than a JavaScript parser because: a) it would considerably slow down module loading, and b) including such a parser in require.js would make it much bigger than it currently.

Community
  • 1
  • 1
Louis
  • 146,715
  • 28
  • 274
  • 320
0

([^:]|^) matches at the beginning of line or a character that is not a colon (:).

It is there to prevent matching URLs like

var a = "http://url.com";

([^:]|^) also captures the text matched, in order to use the backreference $3 as replacement, to put that character back in.


Note though that this expression will also match some cases that are not comments, e.g. in-between quotes.

var b = "this is //not a comment matched";

You should use a JavaScript parser instead.

Community
  • 1
  • 1
Mariano
  • 6,423
  • 4
  • 31
  • 47