mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
refactor(): support matching Meteor projects downwards
Until now the path was only checked upwards for Meteor projects. Now it checks all children recursively. This enables having one common eslint configuration above multiple child directories containing Meteor applications.
This commit is contained in:
8
.meteor/release
Normal file
8
.meteor/release
Normal file
@@ -0,0 +1,8 @@
|
||||
# This is a static file for test purposes.
|
||||
# It simulates the npm package root as being a Meteor Project.
|
||||
#
|
||||
# When requiring lib/index.js (dist/index.js) in tests, that file tries to
|
||||
# find out all possible Meteor project root directories based on cwd before
|
||||
# returning the rules.
|
||||
# To stop it from searching anywhere, the existence of this file simulates the
|
||||
# npm package to be a Meteor project, so the search stops immediately.
|
||||
10
lib/index.js
10
lib/index.js
@@ -1,13 +1,11 @@
|
||||
import getMeteorProjectRootPath from './util/getMeteorProjectRootPath.js'
|
||||
import getProjectRootPaths from './util/getProjectRootPaths'
|
||||
import isMeteorProject from './util/isMeteorProject'
|
||||
|
||||
// const getMeteorProjectRootPath = require('./util/getMeteorProjectRootPath.js');
|
||||
|
||||
const cwd = process.cwd()
|
||||
const rootPath = getMeteorProjectRootPath(cwd)
|
||||
const rootPaths = getProjectRootPaths(process.cwd(), isMeteorProject)
|
||||
|
||||
function unpack (rule) {
|
||||
const packedRule = require(rule)
|
||||
const unpackedRule = packedRule(rootPath)
|
||||
const unpackedRule = packedRule(rootPaths)
|
||||
Object.keys(packedRule).map(function (key) {
|
||||
unpackedRule[key] = packedRule[key]
|
||||
})
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// Rule Definition
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
module.exports = (/* rootPath */) => context => {
|
||||
// const fileInfo = getMeteorMeta(rootPath, context.getFilename())
|
||||
module.exports = (/* rootPaths */) => context => {
|
||||
// const fileInfo = getMeteorMeta(rootPaths, context.getFilename())
|
||||
// console.log(fileInfo)
|
||||
|
||||
// fileInfo is false => not in Meteor Project
|
||||
|
||||
@@ -89,14 +89,27 @@ function getMeteorFileInfo (rootPath, filename) {
|
||||
}
|
||||
}
|
||||
|
||||
export default function getMeteorMeta (rootPath, filename) {
|
||||
function hasFile (parent, filename) {
|
||||
return filename.substr(0, parent.length) === parent
|
||||
}
|
||||
|
||||
if (typeof rootPath === 'object') {
|
||||
export default function getMeteorMeta (rootPaths, filename) {
|
||||
|
||||
// rule is in test-mode. return the given environment
|
||||
return rootPath
|
||||
if (!Array.isArray(rootPaths)) {
|
||||
if (typeof rootPaths === 'object') {
|
||||
|
||||
// rule is in test-mode. return the given environment
|
||||
return rootPaths
|
||||
}
|
||||
|
||||
throw new Error('rootPath must be an Array') // or object for test-mode
|
||||
}
|
||||
|
||||
|
||||
const rootPath = rootPaths.find(function (currentPath) {
|
||||
return hasFile(currentPath, filename)
|
||||
})
|
||||
|
||||
if (!rootPath) {
|
||||
|
||||
// not in a Meteor Project
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
import path from 'path'
|
||||
|
||||
// must be require for rewire to work
|
||||
var pathExists = require('path-exists')
|
||||
|
||||
export default function getMeteorProjectRootPath (currentDirectory) {
|
||||
|
||||
// No folder with '.meteor/release' in it found
|
||||
if (currentDirectory === path.sep) {
|
||||
return false
|
||||
}
|
||||
|
||||
const meteorPath = path.join(currentDirectory, '.meteor', 'release')
|
||||
if (pathExists.sync(meteorPath)) {
|
||||
return currentDirectory
|
||||
}
|
||||
|
||||
return getMeteorProjectRootPath(path.join(currentDirectory, '..'))
|
||||
}
|
||||
48
lib/util/getProjectRootPaths.js
Normal file
48
lib/util/getProjectRootPaths.js
Normal file
@@ -0,0 +1,48 @@
|
||||
import path from 'path'
|
||||
var walk = require('walkdir')
|
||||
|
||||
function findOneUpwards (currentDirectory, matcher, attempts = 0) {
|
||||
|
||||
// No folder with '.meteor/release' in it found
|
||||
if (attempts > 50 || currentDirectory === path.sep) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (matcher(currentDirectory)) {
|
||||
return currentDirectory
|
||||
}
|
||||
|
||||
return findOneUpwards(path.join(currentDirectory, '..'), matcher, attempts + 1)
|
||||
}
|
||||
|
||||
|
||||
function findAllDownwards (startPath, matcher) {
|
||||
const matchedPaths = []
|
||||
const options = {follow_symlinks: false, no_recurse: false, max_depth: 20}
|
||||
walk.sync(
|
||||
startPath,
|
||||
options,
|
||||
function (currentPath) {
|
||||
if (matcher(currentPath)) {
|
||||
matchedPaths.push(currentPath)
|
||||
this.ignore(currentPath)
|
||||
}
|
||||
}
|
||||
)
|
||||
return matchedPaths
|
||||
}
|
||||
|
||||
|
||||
export default function getProjectRootPaths (currentDirectory, matcher) {
|
||||
|
||||
if (matcher(currentDirectory)) {
|
||||
return [currentDirectory]
|
||||
}
|
||||
|
||||
const upwards = findOneUpwards(currentDirectory, matcher)
|
||||
if (upwards) {
|
||||
return [upwards]
|
||||
}
|
||||
|
||||
return findAllDownwards(currentDirectory, matcher)
|
||||
}
|
||||
7
lib/util/isMeteorProject.js
Normal file
7
lib/util/isMeteorProject.js
Normal file
@@ -0,0 +1,7 @@
|
||||
import path from 'path'
|
||||
import pathExists from 'path-exists'
|
||||
|
||||
export default function isMeteorProject (currentDirectory) {
|
||||
const meteorPath = path.join(currentDirectory, '.meteor', 'release')
|
||||
return pathExists.sync(meteorPath)
|
||||
}
|
||||
@@ -13,8 +13,7 @@
|
||||
"prepublish": "npm run build",
|
||||
"semantic-release": "semantic-release pre && npm publish && semantic-release post",
|
||||
"test": "npm run lint && npm run build && npm run unit-test",
|
||||
"unit-test": "istanbul cover --dir reports/coverage node_modules/mocha/bin/_mocha tests/**/*.js -- --reporter dot --compilers js:babel/register",
|
||||
"unit-test:n": "node_modules/mocha/bin/_mocha tests/**/*.js --recursive --reporter dot --compilers js:babel/register"
|
||||
"unit-test": "istanbul cover --dir reports/coverage node_modules/mocha/bin/_mocha tests/**/*.js -- --reporter dot --compilers js:babel/register"
|
||||
},
|
||||
"files": [
|
||||
"LICENSE",
|
||||
@@ -29,7 +28,8 @@
|
||||
"bugs": "https://github.com/dferber90/eslint-plugin-meteor/issues",
|
||||
"dependencies": {
|
||||
"invariant": "2.1.1",
|
||||
"path-exists": "2.0.0"
|
||||
"path-exists": "2.0.0",
|
||||
"walkdir": "0.0.10"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel": "5.8.23",
|
||||
|
||||
@@ -8,6 +8,7 @@ var getMeteorMeta = require('../../../dist/util/getMeteorMeta.js')
|
||||
|
||||
|
||||
const rootPath = path.join('User', 'anon', 'meteor-project')
|
||||
const rootPaths = [rootPath]
|
||||
|
||||
describe('getMeteorMeta', function () {
|
||||
it('has working rule test-mode', function () {
|
||||
@@ -15,9 +16,16 @@ describe('getMeteorMeta', function () {
|
||||
assert.equal(getMeteorMeta(someObj), someObj)
|
||||
})
|
||||
|
||||
it('does not accept anything that is not an object or array', function () {
|
||||
assert.throws(getMeteorMeta.bind(null), Error)
|
||||
assert.throws(getMeteorMeta.bind(null, true), Error)
|
||||
assert.throws(getMeteorMeta.bind(null, false), Error)
|
||||
assert.throws(getMeteorMeta.bind(null, 2), Error)
|
||||
})
|
||||
|
||||
describe('when not in Meteor project', function () {
|
||||
it('returns default env', function () {
|
||||
var result = getMeteorMeta(false, 'file.js')
|
||||
var result = getMeteorMeta([], 'file.js')
|
||||
assert.equal(typeof result, 'object')
|
||||
assert.equal(result.isInMeteorProject, false)
|
||||
assert.equal(Object.keys(result).length, 1)
|
||||
@@ -27,7 +35,7 @@ describe('getMeteorMeta', function () {
|
||||
describe('in public', function () {
|
||||
it('detects the environment', function () {
|
||||
var filename = path.join(rootPath, 'public', 'file.js')
|
||||
var result = getMeteorMeta(rootPath, filename)
|
||||
var result = getMeteorMeta(rootPaths, filename)
|
||||
assert.equal(typeof result, 'object')
|
||||
assert.equal(result.path, 'public/file.js')
|
||||
assert.equal(result.env, ENVIRONMENT.PUBLIC)
|
||||
@@ -39,7 +47,7 @@ describe('getMeteorMeta', function () {
|
||||
describe('in private', function () {
|
||||
it('detects the environment', function () {
|
||||
var filename = path.join(rootPath, 'private', 'file.js')
|
||||
var result = getMeteorMeta(rootPath, filename)
|
||||
var result = getMeteorMeta(rootPaths, filename)
|
||||
assert.equal(typeof result, 'object')
|
||||
assert.equal(result.path, 'private/file.js')
|
||||
assert.equal(result.env, ENVIRONMENT.PRIVATE)
|
||||
@@ -51,7 +59,7 @@ describe('getMeteorMeta', function () {
|
||||
describe('in package', function () {
|
||||
it('detects the environment', function () {
|
||||
var filename = path.join(rootPath, 'packages', 'awesome-pkg', 'file.js')
|
||||
var result = getMeteorMeta(rootPath, filename)
|
||||
var result = getMeteorMeta(rootPaths, filename)
|
||||
assert.equal(typeof result, 'object')
|
||||
assert.equal(result.path, 'packages/awesome-pkg/file.js')
|
||||
assert.equal(result.env, ENVIRONMENT.PACKAGE)
|
||||
@@ -63,7 +71,7 @@ describe('getMeteorMeta', function () {
|
||||
describe('on no special folder', function () {
|
||||
it('has universal environment', function () {
|
||||
var filename = path.join(rootPath, 'file.js')
|
||||
var result = getMeteorMeta(rootPath, filename)
|
||||
var result = getMeteorMeta(rootPaths, filename)
|
||||
assert.equal(typeof result, 'object')
|
||||
assert.equal(result.path, 'file.js')
|
||||
assert.equal(result.env, ENVIRONMENT.UNIVERSAL)
|
||||
@@ -76,7 +84,7 @@ describe('getMeteorMeta', function () {
|
||||
|
||||
it('returns file info', function () {
|
||||
var filename = path.join(rootPath, 'client', 'lib', 'file.js')
|
||||
var result = getMeteorMeta(rootPath, filename)
|
||||
var result = getMeteorMeta(rootPaths, filename)
|
||||
assert.equal(typeof result, 'object')
|
||||
assert.equal(result.path, 'client/lib/file.js')
|
||||
assert.equal(result.env, ENVIRONMENT.CLIENT)
|
||||
@@ -86,7 +94,7 @@ describe('getMeteorMeta', function () {
|
||||
|
||||
it('does not detect compatibility when directly in client-folder ', function () {
|
||||
var filename = path.join(rootPath, 'client', 'file.js')
|
||||
var result = getMeteorMeta(rootPath, filename)
|
||||
var result = getMeteorMeta(rootPaths, filename)
|
||||
assert.equal(typeof result, 'object')
|
||||
assert.equal(result.path, 'client/file.js')
|
||||
assert.equal(result.env, ENVIRONMENT.CLIENT)
|
||||
@@ -96,7 +104,7 @@ describe('getMeteorMeta', function () {
|
||||
|
||||
it('detects compatibility mode', function () {
|
||||
var filename = path.join(rootPath, 'client', 'compatibility', 'file.js')
|
||||
var result = getMeteorMeta(rootPath, filename)
|
||||
var result = getMeteorMeta(rootPaths, filename)
|
||||
assert.equal(typeof result, 'object')
|
||||
assert.equal(result.path, 'client/compatibility/file.js')
|
||||
assert.equal(result.env, ENVIRONMENT.CLIENT)
|
||||
@@ -108,7 +116,7 @@ describe('getMeteorMeta', function () {
|
||||
describe('on server', function () {
|
||||
it('detects the environment', function () {
|
||||
var filename = path.join(rootPath, 'server', 'file.js')
|
||||
var result = getMeteorMeta(rootPath, filename)
|
||||
var result = getMeteorMeta(rootPaths, filename)
|
||||
assert.equal(typeof result, 'object')
|
||||
assert.equal(result.path, 'server/file.js')
|
||||
assert.equal(result.env, ENVIRONMENT.SERVER)
|
||||
@@ -119,7 +127,7 @@ describe('getMeteorMeta', function () {
|
||||
describe('that is nested', function () {
|
||||
it('detects the environment', function () {
|
||||
var filename = path.join(rootPath, 'lib', 'server', 'file.js')
|
||||
var result = getMeteorMeta(rootPath, filename)
|
||||
var result = getMeteorMeta(rootPaths, filename)
|
||||
assert.equal(typeof result, 'object')
|
||||
assert.equal(result.path, 'lib/server/file.js')
|
||||
assert.equal(result.env, ENVIRONMENT.SERVER)
|
||||
@@ -131,7 +139,7 @@ describe('getMeteorMeta', function () {
|
||||
|
||||
describe('in tests', function () {
|
||||
var filename = path.join(rootPath, 'tests', 'file.js')
|
||||
var result = getMeteorMeta(rootPath, filename)
|
||||
var result = getMeteorMeta(rootPaths, filename)
|
||||
assert.equal(typeof result, 'object')
|
||||
assert.equal(result.path, 'tests/file.js')
|
||||
assert.equal(result.env, ENVIRONMENT.TEST)
|
||||
@@ -141,7 +149,7 @@ describe('getMeteorMeta', function () {
|
||||
|
||||
describe('in node_modules', function () {
|
||||
var filename = path.join(rootPath, 'node_modules', 'my-module', 'file.js')
|
||||
var result = getMeteorMeta(rootPath, filename)
|
||||
var result = getMeteorMeta(rootPaths, filename)
|
||||
assert.equal(typeof result, 'object')
|
||||
assert.equal(result.path, 'node_modules/my-module/file.js')
|
||||
assert.equal(result.env, ENVIRONMENT.NODE_MODULE)
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
/* eslint-env mocha */
|
||||
|
||||
var assert = require('assert')
|
||||
var path = require('path')
|
||||
var rewire = require('rewire')
|
||||
var getMeteorProjectRootPath = rewire('../../../dist/util/getMeteorProjectRootPath.js')
|
||||
|
||||
|
||||
var isInMeteorProject
|
||||
getMeteorProjectRootPath.__set__('pathExists', {
|
||||
sync: function () {
|
||||
return isInMeteorProject
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
describe('getMeteorProjectRootPath', function () {
|
||||
it('returns false for top-level directory', function () {
|
||||
assert.equal(getMeteorProjectRootPath(path.sep), false)
|
||||
})
|
||||
|
||||
it('returns false when not in meteor project', function () {
|
||||
isInMeteorProject = false
|
||||
assert.equal(getMeteorProjectRootPath('/not-in-meteor/sub'), false)
|
||||
})
|
||||
|
||||
it('returns the directory when in meteor project', function () {
|
||||
isInMeteorProject = true
|
||||
var meteorPath = '/Users/anon/meteor-project'
|
||||
assert.equal(getMeteorProjectRootPath(meteorPath), meteorPath)
|
||||
})
|
||||
})
|
||||
64
tests/lib/util/getProjectRootPaths.js
Normal file
64
tests/lib/util/getProjectRootPaths.js
Normal file
@@ -0,0 +1,64 @@
|
||||
/* eslint-env mocha */
|
||||
|
||||
var assert = require('assert')
|
||||
var rewire = require('rewire')
|
||||
var getProjectRootPaths = rewire('../../../dist/util/getProjectRootPaths.js')
|
||||
|
||||
var walkShouldFindRoot
|
||||
getProjectRootPaths.__set__('walk', {
|
||||
sync: function (start, options, cb) {
|
||||
var context = {ignore: function () {}}
|
||||
if (walkShouldFindRoot) {
|
||||
cb.call(context, '/User/anon/a/b/meteor-project')
|
||||
cb.call(context, '/User/anon/a/b/c/meteor-project')
|
||||
} else {
|
||||
cb.call(context, '/User/otherguy')
|
||||
cb.call(context, '/User/otherguy/a')
|
||||
cb.call(context, '/User/otherguy/b')
|
||||
cb.call(context, '/User/otherguy/a/b')
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
function matcher (filename) {
|
||||
return (
|
||||
filename === '/User/anon/a/b/meteor-project' ||
|
||||
filename === '/User/anon/a/b/c/meteor-project'
|
||||
)
|
||||
}
|
||||
|
||||
describe('getProjectRootPaths', function () {
|
||||
|
||||
beforeEach(function () {
|
||||
walkShouldFindRoot = true
|
||||
})
|
||||
|
||||
it(`returns an empty array when no project is found`, function () {
|
||||
walkShouldFindRoot = false
|
||||
var result = getProjectRootPaths('/User/otherguy/', matcher)
|
||||
assert.ok(Array.isArray(result))
|
||||
assert.equal(result.length, 0)
|
||||
})
|
||||
|
||||
it(`returns the path when it's the same directory`, function () {
|
||||
var result = getProjectRootPaths('/User/anon/a/b/meteor-project', matcher)
|
||||
assert.equal(result.length, 1)
|
||||
assert.equal(result[0], '/User/anon/a/b/meteor-project')
|
||||
})
|
||||
|
||||
it(`returns a parent Meteor project`, function () {
|
||||
var result = getProjectRootPaths('/User/anon/a/b/meteor-project/a/b/c', matcher)
|
||||
|
||||
assert.equal(result.length, 1)
|
||||
assert.equal(result[0], '/User/anon/a/b/meteor-project')
|
||||
})
|
||||
|
||||
it(`returns all child Meteor projects`, function () {
|
||||
var result = getProjectRootPaths('/User/anon', matcher)
|
||||
|
||||
assert.equal(result.length, 2)
|
||||
assert.equal(result[0], '/User/anon/a/b/meteor-project')
|
||||
assert.equal(result[1], '/User/anon/a/b/c/meteor-project')
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user