Skip to content

Commit

Permalink
Merge pull request #140 from alexkorban/watch-elm-json
Browse files Browse the repository at this point in the history
 Watch Elm package files and get the list of watched directories from them
  • Loading branch information
wking-io authored Oct 3, 2018
2 parents 75fcce7 + 4a38165 commit d4a3b8e
Show file tree
Hide file tree
Showing 6 changed files with 176 additions and 37 deletions.
2 changes: 1 addition & 1 deletion License.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Copyright © 2018 William King, 2015-2018 Tomek Wiszniewski, 2016 Brian Dukes
Copyright © 2018 William King, 2018 Alex Korban, 2015-2018 Tomek Wiszniewski, 2016 Brian Dukes

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

Expand Down
72 changes: 50 additions & 22 deletions source/elm-live.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ module.exports = (argv, options) => {
const elmServe = require('elm-serve')
const chokidar = require('chokidar')
const debounce = require('./debounce')
const getSourceDirs = require("./get-source-dirs")

const auxiliaryBuild = execPath => {
const process = spawnSync(execPath, [], {
Expand Down Expand Up @@ -186,33 +187,60 @@ ${chalk.dim('elm-live:')}
unlinkDir: 'removed'
}

// Watch Elm files
const watcher = chokidar.watch('**/*.elm', {
ignoreInitial: true,
followSymlinks: false,
ignored: 'elm-stuff/generated-code/*'
})
const packageFileNames = ['elm.json', 'elm-package.json']

watcher.on(
'all',
debounce((event, filePath) => {
const relativePath = path.relative(process.cwd(), filePath)
const eventName = eventNameMap[event] || event
const isPackageFilePath = (relativePath) => {
return packageFileNames.indexOf(relativePath) > -1
}

outputStream.write(
`
const watchElmFiles = () => {
const sourceDirs = getSourceDirs()

outputStream.write(
`
${chalk.dim('elm-live:')}
Watching ${sourceDirs.join(", ")}.
`
)

let watcher = chokidar.watch(sourceDirs.concat(packageFileNames), {
ignoreInitial: true,
followSymlinks: false,
ignored: 'elm-stuff/generated-code/*'
})

watcher.on(
'all',
debounce((event, filePath) => {
const relativePath = path.relative(process.cwd(), filePath)
const eventName = eventNameMap[event] || event

outputStream.write(
`
${chalk.dim('elm-live:')}
You’ve ${eventName} \`${relativePath}\`. Rebuilding!
`
)
)

const buildResult = build()
if (!serverStarted && buildResult.exitCode === SUCCESS) {
startServer()
}

if (isPackageFilePath(relativePath)) {
// Package file changes may result in changes to the set
// of watched files
watcher.close()
watcher = watchElmFiles()
}
}),
100
)
}

watchElmFiles()

const buildResult = build()
if (!serverStarted && buildResult.exitCode === SUCCESS) {
startServer()
}
}),
100
)
return null
}
38 changes: 38 additions & 0 deletions source/get-source-dirs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
const path = require('path')
const fs = require('fs')

const defaultElmDirs = ['**/*.elm']

function getSourceDirs(packageFilePath) {
try {
const elmPackage = JSON.parse(fs.readFileSync(packageFilePath))
const sourceDirs = elmPackage['source-directories']
if (sourceDirs !== undefined) {
return sourceDirs.map(dir => path.join(dir, '/**/*.elm'))
}
else {
return defaultElmDirs
}
}
catch (e) {
// Do nothing about the exception (in parsing JSON) because the Elm compiler
// will also parse the file and report the error - and elm-live will show it
// to the user. We don't want to report the same error twice.
return defaultElmDirs
}
}

module.exports = (workPath = process.cwd()) => {
const elmJsonPath = path.join(workPath, 'elm.json')
const elmPackageJsonPath = path.join(workPath, 'elm-package.json')

if (fs.existsSync(elmJsonPath)) {
return getSourceDirs(elmJsonPath)
}
else if (fs.existsSync(elmPackageJsonPath)) {
return getSourceDirs(elmPackageJsonPath)
}
else {
return defaultElmDirs
}
}
61 changes: 47 additions & 14 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const devnull = require('dev-null')
const qs = require('q-stream')
const naked = require('strip-ansi')
const debounce = require('./source/debounce')
const getSourceDirs = require('./source/get-source-dirs')

const dummyConfig = { inputStream: devnull(), outputStream: devnull() }
const dummyCrossSpawn = { sync: () => ({ status: 0 }) }
Expand Down Expand Up @@ -323,9 +324,9 @@ test('Starts elmServe and chokidar with correct config', assert => {

const chokidar = {
watch: glob => {
assert.is(
assert.deepEqual(
glob,
'**/*.elm',
['**/*.elm', 'elm.json', 'elm-package.json'],
'watches all `*.elm` files in the current directory ' +
'and its subdirectories'
)
Expand Down Expand Up @@ -425,7 +426,7 @@ test('`--pushstate to support client-side routing', assert => {

test('Watches all `**/*.elm` files in the current directory', assert =>
new Promise(resolve => {
assert.plan(6)
assert.plan(7)

const event = 'change'
const relativePath = path.join('ab', 'c.elm')
Expand All @@ -439,7 +440,8 @@ test('Watches all `**/*.elm` files in the current directory', assert =>

const chokidar = {
watch: (target, options) => {
assert.is(target, '**/*.elm', 'passes the right glob to chokidar')
assert.deepEqual(target, ['**/*.elm', 'elm.json', 'elm-package.json'],
'passes the right glob to chokidar')

assert.true(
options.ignoreInitial,
Expand Down Expand Up @@ -494,23 +496,54 @@ test('Watches all `**/*.elm` files in the current directory', assert =>
inputStream: devnull(),
outputStream: qs(chunk => {
chunkNumber++
if (chunkNumber !== 3) return

assert.is(
naked(chunk),
`
if (chunkNumber == 3) {
assert.is(
naked(chunk),
`
elm-live:
Watching **/*.elm.
`,
'prints a message with watched paths'
)
}
else if (chunkNumber == 4) {
assert.is(
naked(chunk),
`
elm-live:
You’ve changed \`${relativePath}\`. Rebuilding!
`,
'prints a message when a file is changed'
)

resolve()
'prints a message when a file is changed'
)

resolve()
}
})
})
}))

test("gets watched paths from the Elm package file", assert => {
const testSourceDirs = (testDir, expectedDirs) => {
const sourceDirs = getSourceDirs(testDir)
const msg = `get elm dirs: ${sourceDirs}, expected: ${expectedDirs}`
assert.deepEqual(sourceDirs, expectedDirs, msg)
}

new Promise(resolve => {
assert.plan(3)

testSourceDirs("test/0.18.0", ["src18/**/*.elm", "../elsewhere18/src/**/*.elm"])

testSourceDirs("test/0.19.0", ["src19/**/*.elm", "../../elsewhere19/**/*.elm"])

testSourceDirs("test", ["**/*.elm"])

resolve()
})
})

test('--before-build and --after-build work', assert =>
new Promise(resolve => {
const beforeCommand = 'run-me-beforehand'
Expand Down
16 changes: 16 additions & 0 deletions test/0.18.0/elm-package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"version": "1.0.0",
"summary": "Project",
"repository": "https://github.com/user/project.git",
"license": "BSD3",
"source-directories": [
"src18", "../elsewhere18/src"
],
"exposed-modules": [],
"dependencies": {
"elm-lang/core": "5.1.1 <= v < 6.0.0",
"elm-lang/html": "2.0.0 <= v < 3.0.0",
"elm-lang/http": "1.0.0 <= v < 1.1.0"
},
"elm-version": "0.18.0 <= v < 0.19.0"
}
24 changes: 24 additions & 0 deletions test/0.19.0/elm.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"type": "application",
"source-directories": [
"src19", "../../elsewhere19"
],
"elm-version": "0.19.0",
"dependencies": {
"direct": {
"elm/browser": "1.0.0",
"elm/core": "1.0.0",
"elm/html": "1.0.0"
},
"indirect": {
"elm/json": "1.0.0",
"elm/time": "1.0.0",
"elm/url": "1.0.0",
"elm/virtual-dom": "1.0.2"
}
},
"test-dependencies": {
"direct": {},
"indirect": {}
}
}

0 comments on commit d4a3b8e

Please sign in to comment.