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

Improve watcher #475

Merged
merged 67 commits into from
Dec 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
28c4f95
First pass at better watcher
lydell Nov 18, 2020
2355d3d
Fix chdir
lydell Nov 18, 2020
11f99c4
Get rid of arbitrary split
lydell Nov 18, 2020
762e3f7
Remove unnecessary path.resolve
lydell Nov 18, 2020
5764ced
Replace dead code
lydell Nov 18, 2020
24cd9cf
Update .flowconfig
lydell Nov 19, 2020
125fd8c
Initial pass at ElmJson.js
lydell Nov 19, 2020
a9ada09
Fix error message
lydell Nov 19, 2020
a17f07a
Get rid of the last `any` annotations
lydell Nov 19, 2020
1c4d753
ElmJson.getPath
lydell Nov 19, 2020
a2e61c3
Simplify
lydell Nov 19, 2020
9c55e25
Remove resolved TODO comment
lydell Nov 19, 2020
b64079d
Refactor into a Project type
lydell Nov 19, 2020
101b96c
Make globs watcher globs independent of cwd
lydell Nov 19, 2020
ae0e6bf
Inline make
lydell Nov 19, 2020
a278b6e
Concentrate console.log into elm-test.js and Supervisor.js
lydell Nov 19, 2020
ed3e1e3
Don’t clear console for json and junit
lydell Nov 19, 2020
3699ef7
Move some functions to top level
lydell Nov 19, 2020
06b5c68
Move pipe filename to its own function
lydell Nov 19, 2020
9044e5f
Fix typo
lydell Nov 19, 2020
ce7ca74
Fix tests
lydell Nov 19, 2020
f96da98
Fix globbing
lydell Nov 19, 2020
fbd0d5b
Fix `elm-test tests src`
lydell Nov 19, 2020
22392ac
Optimize watching
lydell Nov 19, 2020
aa22a6b
Queue runs
lydell Nov 19, 2020
4467759
Batch events that happen roughly at the same time
lydell Nov 19, 2020
e79bea8
Always watch tests/
lydell Nov 19, 2020
7a2b5f6
Make init and install commands code less noisy
lydell Nov 19, 2020
f78c221
Remove last `var` in Solve.js
lydell Nov 19, 2020
656112d
Use object shorthand
lydell Nov 20, 2020
3df45e9
Rename Runner.js to FindTests.js
lydell Nov 20, 2020
0212108
Move more code related to finding tests to FindTests.js
lydell Nov 20, 2020
a0fe808
Move code for running the tests to RunTests.js
lydell Nov 20, 2020
2a6c832
Remove .js prefix from require
lydell Nov 20, 2020
25cab7f
Use cross-spawn when installing packages
lydell Nov 20, 2020
4220502
Concentrate process.exit into elm-test.js
lydell Nov 20, 2020
fe97919
Add ElmJson tests
lydell Nov 20, 2020
72b8f0e
Test that elm.json is watched
lydell Nov 20, 2020
7e5901b
Test adding and removing files
lydell Nov 20, 2020
53310e0
Test finding elm.json up the directory tree
lydell Nov 20, 2020
1611825
Document how crazy big files are handled
lydell Nov 20, 2020
9945d4a
Add tests for watch + init
lydell Nov 20, 2020
dcdb863
Improve error message when source-directories contains "."
lydell Nov 21, 2020
9d87dcc
Validate source directories
lydell Nov 21, 2020
9778eb7
Fix tests after added .gitignore
lydell Nov 21, 2020
76f0dec
Fix paths in test snapshots
lydell Nov 21, 2020
f4f6a68
Try a different approach for resolving globs
lydell Nov 21, 2020
45d993f
Don’t trigger test runs on non-elm file changes in tests/
lydell Nov 21, 2020
a5604c2
Update outdated comments
lydell Nov 21, 2020
081dc67
Improve globbing
lydell Nov 21, 2020
8e45355
Deduplicate test files
lydell Nov 21, 2020
46299d9
Normalize paths on Windows
lydell Nov 21, 2020
0f1e697
Reduce delay
lydell Nov 21, 2020
9e11a05
Use async/await in tests/Parser.js
lydell Nov 21, 2020
62007fb
Fix tests on Windows
lydell Nov 21, 2020
d2c09cf
Fix another test on Windows
lydell Nov 21, 2020
e9280de
Code review
lydell Nov 28, 2020
a426c29
Trigger build
lydell Nov 28, 2020
46d7f77
Make sure elm-stuff doesn’t grow indefinitely
lydell Dec 8, 2020
9ca9939
Remove outdated comment
lydell Dec 12, 2020
e1a1a45
Simplify after.js now that we always know the module name
lydell Dec 12, 2020
be5aa85
Remove unnecessary mutation when creating elm.json
lydell Dec 12, 2020
e1469b3
Better variable name: installationScratchDir
lydell Dec 12, 2020
b5f5b73
Add missing newline at the end of a file
lydell Dec 12, 2020
596eb62
Improve comment in elm-test.js
lydell Dec 12, 2020
261b1a9
Replace `findClosest` with `findClosestElmJson`
lydell Dec 12, 2020
43b76cc
Enable Flow’s unclear-type lint rule
lydell Dec 12, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 5 additions & 9 deletions .flowconfig
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
[ignore]

.*elm.json

[include]

[libs]

[options]
include_warnings=true
exact_by_default=true

module.ignore_non_literal_requires=true
[lints]
all=error
untyped-import=off
18 changes: 0 additions & 18 deletions flow-typed/Result.js

This file was deleted.

39 changes: 13 additions & 26 deletions lib/Compile.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
//@flow

const spawn = require('cross-spawn');
const path = require('path');
const packageInfo = require('../package.json');
const ElmCompiler = require('./ElmCompiler');
const Report = require('./Report');

function compile(
cwd /*: string */,
testFile /*: string */,
dest /*: string */,
pathToElmBinary /*: string */,
Expand All @@ -15,7 +14,7 @@ function compile(
return new Promise((resolve, reject) => {
const compileProcess = ElmCompiler.compile([testFile], {
output: dest,
spawn: spawnCompiler({ ignoreStdout: true }),
spawn: spawnCompiler({ ignoreStdout: true, cwd }),
pathToElm: pathToElmBinary,
processOpts: processOptsForReporter(report),
});
Expand All @@ -30,21 +29,6 @@ function compile(
});
}

function getGeneratedCodeDir(projectRootDir /*: string */) /*: string */ {
return path.join(
projectRootDir,
'elm-stuff',
'generated-code',
'elm-community',
'elm-test',
packageInfo.version
);
}

function getTestRootDir(projectRootDir /*: string */) /*: string */ {
return path.resolve(path.join(projectRootDir, 'tests'));
}
harrysarson marked this conversation as resolved.
Show resolved Hide resolved

function compileSources(
testFilePaths /*: Array<string> */,
projectRootDir /*: string */,
Expand All @@ -57,7 +41,7 @@ function compileSources(
const compileProcess = ElmCompiler.compile(testFilePaths, {
output: '/dev/null',
cwd: projectRootDir,
spawn: spawnCompiler({ ignoreStdout: false }),
spawn: spawnCompiler({ ignoreStdout: false, cwd: projectRootDir }),
pathToElm: pathToElmBinary,
report: compilerReport,
processOpts: processOptsForReporter(report),
Expand All @@ -73,25 +57,30 @@ function compileSources(
});
}

function spawnCompiler({ ignoreStdout }) {
function spawnCompiler({ ignoreStdout, cwd }) {
return (
pathToElm /*: string */,
processArgs /*: Array<string> */,
processOpts /*: Object */
processOpts /*: child_process$spawnOpts */
) => {
const finalOpts = Object.assign({ env: process.env }, processOpts, {
const finalOpts = {
env: process.env,
...processOpts,
cwd,
stdio: [
process.stdin,
ignoreStdout ? 'ignore' : process.stdout,
process.stderr,
],
});
};

return spawn(pathToElm, processArgs, finalOpts);
};
}

function processOptsForReporter(report /*: typeof Report.Report */) {
function processOptsForReporter(
report /*: typeof Report.Report */
) /*: child_process$spawnOpts */ {
if (Report.isMachineReadable(report)) {
return { env: process.env, stdio: ['ignore', 'ignore', process.stderr] };
} else {
Expand All @@ -102,6 +91,4 @@ function processOptsForReporter(report /*: typeof Report.Report */) {
module.exports = {
compile,
compileSources,
getTestRootDir,
getGeneratedCodeDir,
};
193 changes: 193 additions & 0 deletions lib/ElmJson.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
// @flow

const fs = require('fs');
const path = require('path');

// Poor man’s type alias. We can’t use /*:: type Dependencies = ... */ because of:
// https://github.com/prettier/prettier/issues/2597
const Dependencies /*: { [string]: string } */ = {};

const DirectAndIndirectDependencies /*: {
direct: typeof Dependencies,
indirect: typeof Dependencies,
} */ = { direct: {}, indirect: {} };

const ElmJson /*:
| {
type: 'application',
'source-directories': Array<string>,
dependencies: typeof DirectAndIndirectDependencies,
'test-dependencies': typeof DirectAndIndirectDependencies,
[string]: mixed,
}
| {
type: 'package',
dependencies: typeof Dependencies,
'test-dependencies': typeof Dependencies,
[string]: mixed,
} */ = {
type: 'package',
dependencies: Dependencies,
'test-dependencies': Dependencies,
};

function getPath(dir /*: string */) /*: string */ {
return path.join(dir, 'elm.json');
}

function write(dir /*: string */, elmJson /*: typeof ElmJson */) /*: void */ {
const elmJsonPath = getPath(dir);

try {
fs.writeFileSync(elmJsonPath, JSON.stringify(elmJson, null, 4) + '\n');
} catch (error) {
throw new Error(
`${elmJsonPath}\nFailed to write elm.json:\n${error.message}`
);
}
}

function read(dir /*: string */) /*: typeof ElmJson */ {
const elmJsonPath = getPath(dir);

try {
return readHelper(elmJsonPath);
} catch (error) {
throw new Error(
`${elmJsonPath}\nFailed to read elm.json:\n${error.message}`
);
}
}

function readHelper(elmJsonPath /*: string */) /*: typeof ElmJson */ {
const json = parseObject(
JSON.parse(fs.readFileSync(elmJsonPath, 'utf8')),
harrysarson marked this conversation as resolved.
Show resolved Hide resolved
'the file'
);

switch (json.type) {
case 'application':
return {
...json,
type: 'application',
'source-directories': parseSourceDirectories(
json['source-directories']
),
dependencies: parseDirectAndIndirectDependencies(
json.dependencies,
'dependencies'
),
'test-dependencies': parseDirectAndIndirectDependencies(
json['test-dependencies'],
'test-dependencies'
),
};

case 'package':
return {
...json,
type: 'package',
dependencies: parseDependencies(json.dependencies, 'dependencies'),
'test-dependencies': parseDependencies(
json['test-dependencies'],
'test-dependencies'
),
};

default:
throw new Error(
`Expected "type" to be "application" or "package", but got: ${stringify(
json.type
)}`
);
}
}

function parseSourceDirectories(json /*: mixed */) /*: Array<string> */ {
if (!Array.isArray(json)) {
throw new Error(
`Expected "source-directories" to be an array, but got: ${stringify(
json
)}`
);
}

const result = [];

for (const [index, item] of json.entries()) {
if (typeof item !== 'string') {
throw new Error(
`Expected "source-directories"->${index} to be a string, but got: ${stringify(
item
)}`
);
}
result.push(item);
}

if (result.length === 0) {
throw new Error(
'Expected "source-directories" to contain at least one item, but it is empty.'
);
}

return result;
}

function parseDirectAndIndirectDependencies(
json /*: mixed */,
what /*: string */
) /*: typeof DirectAndIndirectDependencies */ {
const jsonObject = parseObject(json, what);
return {
direct: parseDependencies(jsonObject.direct, `${what}->"direct"`),
indirect: parseDependencies(jsonObject.indirect, `${what}->"indirect"`),
};
}

function parseDependencies(
json /*: mixed */,
what /*: string */
) /*: typeof Dependencies */ {
const jsonObject = parseObject(json, what);
const result = {};

for (const [key, value] of Object.entries(jsonObject)) {
if (typeof value !== 'string') {
throw new Error(
`Expected ${what}->${stringify(
key
)} to be a string, but got: ${stringify(value)}`
);
}
result[key] = value;
}

return result;
}

function parseObject(
json /*: mixed */,
what /*: string */
) /*: { +[string]: mixed } */ {
if (json == null || typeof json !== 'object' || Array.isArray(json)) {
throw new Error(
`Expected ${what} to be an object, but got: ${stringify(json)}`
);
}
return json;
}

function stringify(json /*: mixed */) /*: string */ {
const maybeString = JSON.stringify(json);
harrysarson marked this conversation as resolved.
Show resolved Hide resolved
return maybeString === undefined ? 'undefined' : maybeString;
}

module.exports = {
DirectAndIndirectDependencies,
ElmJson,
getPath,
parseDirectAndIndirectDependencies,
read,
write,
};
Loading