Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check for Node’s fs and path before trying to use them #339

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

GeoffreyBooth
Copy link

@GeoffreyBooth GeoffreyBooth commented Jan 21, 2017

lrGeneratorMixin.generateCommonJSModule generates some code that is intended to run in a CommonJS environment, within which it takes for granted that Node’s fs and path will be available. This may not necessarily be the case, as is demonstrated in jashkenas/coffeescript#4391. We should simply check that require('fs') and require('path') are defined before we try to use them.

…environment that happens to have `require` and `exports` defined as globals
@GeoffreyBooth GeoffreyBooth changed the title Improve test for CommonJS environment Check for Node’s fs and path before trying to use them Jan 21, 2017
…quire(‘fs’) returns something before we try to use it
@@ -1280,7 +1280,12 @@ function commonjsMain (args) {
console.log('Usage: '+args[0]+' FILE');
process.exit(1);
}
var source = require('fs').readFileSync(require('path').normalize(args[1]), "utf8");
var source = null;
Copy link

@lydell lydell Jan 21, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can exports.parser.parse(source) (a few lines below) handle source === null?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, it can't. Expected input is string, always. (... I now see you tweaked for that already.)

@@ -1280,7 +1280,12 @@ function commonjsMain (args) {
console.log('Usage: '+args[0]+' FILE');
process.exit(1);
}
var source = require('fs').readFileSync(require('path').normalize(args[1]), "utf8");
var source = null;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, it can't. Expected input is string, always. (... I now see you tweaked for that already.)

var path = require('path');
if (typeof fs !== 'undefined' && fs !== null && typeof path !== 'undefined' && path !== null) {
source = fs.readFileSync(path.normalize(args[1]), "utf8");
}
return exports.parser.parse(source);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And given that you want to code this defensively, wouldn't it be better to code it as a feature detect, i.e. along the lines of if (fs && typeof fs.readFileSync === 'function' && path && typeof path.normalize === 'function') { source = ...?

Besides, now that you start with an empty string a 'default input if fs/path don't exist in my env', which would very probably throw a parse error (on empty input) anyway, why the source = '' change? Right now you have a situation where, if readFilesync doesn't deliver, you end up with unusable input anyway (it'll always execute parser.parse("") then) so I wonder what you want to accomplish in a non-readFileSync environment. Maybe 'overload' the interface where

if (typeof args === 'string') {
  // not using readFileSync, but feeding it the input straight away:
  return exports.parser.parse(args);
} else {
  if (readFileSync does not exist || args[] is not array) {
    throw Error('barfing hairball, mentioning unexpected environment situation?');
  } else {
    return ...parse(source); // loaded from file: args[1], i.e. args MUST be array
  }
}

That would at least make the CommonJS interface usable in both situations and add meaning to your checks; right now, all I see is a change in the way this will crash/fail. 😕

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is getting included inside the browser-based CoffeeScript compiler. The use case for these checks is when someone is using the compiler in a project that has require.js, which basically simulates a CommonJS environment. See jashkenas/coffeescript#4391. I’m trying to make things not crash in such an environment.

Perhaps the return exports.parser.parse(source); could be inside the if, and this function returns nothing when readFileSync is unavailable; I didn’t try that. I’m under the impression though that downstream tools need whatever this function is returning, even if it’s a parsing of an empty string.

@GerHobbelt
Copy link
Contributor

related: #320

@GeoffreyBooth
Copy link
Author

There’s a workaround, per jashkenas/coffeescript#4546:

var parser = require('./lib/coffeescript/grammar').parser.generate({
  moduleMain: function() {}
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants