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

Support multiple source directories #1

Merged
merged 4 commits into from
Mar 23, 2017

Conversation

sentience
Copy link
Contributor

elm-package.json may specify multiple source directories for a single Elm project (e.g. application modules and library modules). Modules in one source directory may import modules in another source directory transparently.

With this change, we now find the elm-package.json file responsible for the requested module and use it to search all of the project’s source directories for each dependency.

elm-package.json may specify multiple source directories for a single Elm project (e.g. application modules and library modules). Modules in one source directory may import modules in another source directory transparently.

With this change, we now find the elm-package.json file responsible for the requested module and use it to search all of the project’s source directories for each dependency.
@sentience
Copy link
Contributor Author

sentience commented Mar 22, 2017

We’re hoping to get this merged and released in elm-webpack-loader (via node-elm-compiler), so that we can use webpack --watch reliably with our multi-source-dir project.

@stoeffel stoeffel self-requested a review March 22, 2017 20:56
Copy link
Contributor

@stoeffel stoeffel left a comment

Choose a reason for hiding this comment

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

Thanks for your PR ❤️. Code looks great. I had just one minor comment.

index.js Outdated
}
}

// Given a source directory (containing top-level Elm modules), locate the
// elm-package.json file that includes it.
function findElmPackage(baseDir, currentDir) {
Copy link
Contributor

Choose a reason for hiding this comment

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

🎨 we can drop currentDir and just use one arg.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

My intent here was to preserve baseDir through the recursion so that when we found the elm-package.json file, we could verify that the baseDir in question was actually listed in its source-directories, but I ended up not writing this check. What do you think? Would this level of robustness be useful? Or is it sufficient just to search up through parent directories and use the first elm-package.json file that we find (in which case I will delete the unneeded variable).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thinking about it some more, I’m thinking we probably should check that the source-directories does contain baseDir. If not, and the elm-package.json contains source directories that don’t match, find-elm-dependencies is going to be unable to find any dependencies in that baseDir, and it will be really confusing.

I’ll update this and include a test case.

@sentience
Copy link
Contributor Author

@stoeffel OK, should be good to go now.

@sentience
Copy link
Contributor Author

Important to note this changes the API signature for the exported findAllDependencies function (sourceDirectories takes an array whereas baseDir took a string), so if you’re doing Semver you’ll need to increment the major version for this change. I assumed no one was depending on that argument’s type at this point.

@stoeffel
Copy link
Contributor

@sentience The cli doesn't work anymore.

$ ./bin/cli.js ./test/fixtures/Parent.elm
[]

Would you mind fixing that? Let me know if you need help.

index.js Outdated
if (typeof currentDir === "undefined") {
currentDir = baseDir;
}

var elmPackagePath = path.join(currentDir, 'elm-package.json');
if (fs.existsSync(elmPackagePath)) {
return elmPackagePath;
var sourceDirectories = getSourceDirectories(elmPackagePath);
if (_.includes(sourceDirectories, baseDir)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm worried that this never halts, when this isn't true. I think this should raise an error. I also think that the source-directories don't have to include base dir right? You could have a elm-package with only ./src.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It will halt when the search for a matching elm-package.json reaches the root directory of the file system (see return false; on line 89).

Basically we ignore the “bad” elm-package.json file and continue searching up the path for a “good” elm-package.json file. If we never find one, we give up when we get to the filesystem root.

Hope that makes sense!

Copy link
Contributor

Choose a reason for hiding this comment

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

Makes sense, but:

I also think that the source-directories don't have to include base dir right? You could have a elm-package with only ./src.

Copy link
Contributor Author

@sentience sentience Mar 23, 2017

Choose a reason for hiding this comment

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

Correct, and that’s supported by my implementation already. If you have:

my-package
`- elm-package.json ("source-directories": ["./src"])
`- src
    `- Main.elm (module Main exposing (..))

…then getBaseDir('/path/to/src/Main.elm') will return /path/to/src, and then getElmPackageSourceDirectories('/path/to/src') will find elm-package.json in the parent directory, confirm it includes ./src in "source-directories" and return ['/path/to/src'].

Unless I’m missing something?

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh, you're right!

@sentience
Copy link
Contributor Author

Taking a look at the CLI now.

@sentience
Copy link
Contributor Author

CLI is fixed. Good catch!

@stoeffel stoeffel merged commit 873f939 into NoRedInk:master Mar 23, 2017
@stoeffel
Copy link
Contributor

Thanks for your contribution.

@stoeffel
Copy link
Contributor

published with v1.0.0

@sentience sentience deleted the multiple-src-dirs branch March 23, 2017 23:34
// elm-package.json file that includes it and get all its source directories.
function getElmPackageSourceDirectories(baseDir, currentDir) {
if (typeof currentDir === "undefined") {
currentDir = baseDir = path.resolve(baseDir);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please set this on multiple lines, this is prone to error.

}

if (isRoot(currentDir)) {
return false;
Copy link
Collaborator

Choose a reason for hiding this comment

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

What is the type of this function meant to be? Make it return an empty list instead of a bool.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch!


function findAllDependenciesHelp(file, knownDependencies, baseDir, knownFiles) {
function getSourceDirectories(elmPackagePath) {
var elmPackage = JSON.parse(fs.readFileSync(elmPackagePath, 'utf8'));
Copy link
Collaborator

Choose a reason for hiding this comment

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

this will crash if there is invalid json, with a bad error message. Good to catch it and return an empty list instead.

_.find(sourceDirectories, function(sourceDir) {
var absPath = path.join(sourceDir, dependencyLogicalName + extension);
if (fs.existsSync(absPath)) {
result = absPath;
Copy link
Collaborator

Choose a reason for hiding this comment

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

why use mutation? Do result = _.find(...)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The mutation avoids having to either map all entries to absolute paths, or having to map the found result a second time after returning it. I'm happy to go with either one if you consider this an unwanted optimisation.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I'd rather spend milliseconds on avoiding crashes than hours debugging :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

👍

@eeue56
Copy link
Collaborator

eeue56 commented Mar 24, 2017

@sentience I have some concerns with the code that I'd like addressed before using the webpack-loader to rely on this. I've commented on the diff.

@sentience
Copy link
Contributor Author

Thanks for the review! I'll open a second PR with the requested improvements to release as 1.0.1.

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