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

Lint JavaScript snippets in the documentation #480

Merged
merged 30 commits into from Jan 22, 2019
Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
c78fb3f
Add and configure eslint-plugin-markdown
papandreou May 27, 2018
990d2a8
Disable the no-unused-vars and no-undef rules
papandreou Jan 10, 2019
b7a747c
eslint --fix --ext js,md .
papandreou Jan 10, 2019
5017ac1
Use the HTML comment syntax for passing evaluate:false to one of the …
papandreou Jan 10, 2019
26dce84
Pass async:true as an HTML comment in another place
papandreou Jan 10, 2019
ac3ed54
Convert ```js#flags to preceding HTML comments
papandreou Jan 10, 2019
b24062a
Convert the last couple of non-standard cases manually
papandreou Jan 10, 2019
0c80ee8
eslint --fix --ext js,md .
papandreou Jan 10, 2019
74f3cea
Update unexpected-markdown to ^2.1.0
papandreou Jan 10, 2019
8857859
Update unexpected-documentation-site-generator to ^5.2.0
papandreou Jan 10, 2019
0180745
Switch to esprima and parse in tolerant mode to allow global return
papandreou Jan 11, 2019
7e4d707
eslint --fix --ext md documentation/
papandreou Jan 11, 2019
1538c0f
Remove unnecessary 'new' operator from the migration guide
papandreou Jan 11, 2019
1ed057a
Use the old js#evaluate:false syntax for snippets that aren't valid J…
papandreou Jan 11, 2019
52f9acf
Fix the last error by specifying expect:true in the eslint global set…
papandreou Jan 11, 2019
67714b6
Avoid linting .md files in the root dir as JavaScript
papandreou Jan 11, 2019
02546a5
Comment on why we're disabling lint rules
papandreou Jan 12, 2019
77f4386
Get globalReturn to work with espree by providing sourceType:script
papandreou Jan 12, 2019
80a7f09
Merge branch 'master' into feature/lint-markdown
papandreou Jan 15, 2019
c1eb08f
Merge branch 'master' into feature/lint-markdown
papandreou Jan 15, 2019
3209f4a
Fix new lint errors from #578
papandreou Jan 15, 2019
cd98e4f
perl -pi -e 's/<!-- (.*)-->/<!-- unexpected-markdown $1-->/g;' `find …
papandreou Jan 16, 2019
0761da9
Fix old, no longer supported unexpected-markdown construct
papandreou Jan 16, 2019
ce148f9
Order depdendencies asciibetically
papandreou Jan 17, 2019
4f41fbf
Update unexpected-documentation-site-generator to ^6.0.0 and unexpect…
papandreou Jan 18, 2019
89f17f5
Disable import/no-extraneous-dependencies only where necessary instea…
papandreou Jan 18, 2019
10d2711
Regain syntax highlighting of ```js blocks that don't parse
papandreou Jan 18, 2019
96caa8a
Remove no longer necessary .eslintrc.js directive
papandreou Jan 18, 2019
1090605
Merge branch 'master' into feature/lint-markdown
papandreou Jan 22, 2019
c861ab8
Fix glitches in flags for js blocks
papandreou Jan 22, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 0 additions & 1 deletion .eslintignore
@@ -1,4 +1,3 @@
/documentation/
/images/
/build/
/vendor/
Expand Down
14 changes: 14 additions & 0 deletions documentation/.eslintrc.js
@@ -0,0 +1,14 @@
module.exports = {
root: false,
plugins: ['markdown'],
rules: {
// Some snippets reference variables from previous ones
// but eslint-plugin-markdown lints them independently.
// Disable the rules that this causes trouble with:
'no-unused-vars': 0,
'no-undef': 0
},
parserOptions: {
sourceType: 'script' // Otherwise globalReturn won't work, we use that for the async snippets
}
};
3 changes: 2 additions & 1 deletion documentation/api/UnexpectedError.md
Expand Up @@ -18,7 +18,8 @@ shortcut you can also just pass the output or format directly.
An alternative to calling `getErrorMessage(output)` with an output,
you can append the error message to an output the following way:

```js#evaluate:false
<!-- unexpected-markdown evaluate:false -->
```js
output.appendErrorMessage(error);
```

Expand Down
31 changes: 23 additions & 8 deletions documentation/api/addAssertion.md
Expand Up @@ -2,7 +2,9 @@

Signature:

```js#evaluate:false
<!-- unexpected-markdown evaluate:false -->
<!-- eslint-skip -->
```js
expect.addAssertion(pattern, handler);
expect.addAssertion([pattern, ...]], handler);
```
Expand Down Expand Up @@ -63,15 +65,18 @@ type and pattern of the assertion.

So in this case, when `expect` is called the following way:

```js#evaluate:false
expect([3,2,1], 'to be sorted', reverse);
<!-- unexpected-markdown evaluate:false -->
```js
expect([3, 2, 1], 'to be sorted', reverse);
```

The handler to our assertion will be called with the values the
following way, where the _not_ flag in the nested expect will be
removed:

```js#evaluate:false
<!-- unexpected-markdown evaluate:false -->
<!-- eslint-skip -->
```js
expect.addAssertion('<array> [not] to be (sorted|ordered) <function?>', function(expect, [3,2,1], reverse){
expect([3,2,1], '[not] to equal', [].concat([3,2,1]).sort(reverse));
});
Expand Down Expand Up @@ -286,8 +291,13 @@ It would be pretty nice if we could use
even if the retrieval is delayed. Then we would be able to do stuff
like this:

```js#evaluate:false
return expect(new Timelock('Hello world'), 'to satisfy', expect.it('have length', 11));
<!-- unexpected-markdown evaluate:false -->
```js
return expect(
new Timelock('Hello world'),
'to satisfy',
expect.it('have length', 11)
);
```

First we need to define a [type](../addType/) for handling the `Timelock`:
Expand Down Expand Up @@ -322,8 +332,13 @@ expect.addAssertion('<Timelock> to satisfy <any>', function(

Let's see how it works:

```js#async:true
return expect(new Timelock('Hello world!', 5), 'to satisfy', expect.it('not to match', /!/));
<!-- unexpected-markdown async:true -->
```js
return expect(
new Timelock('Hello world!', 5),
'to satisfy',
expect.it('not to match', /!/)
);
```

```output
Expand Down
201 changes: 110 additions & 91 deletions documentation/api/addType.md
Expand Up @@ -94,20 +94,22 @@ That is already quite helpful, but it would be even nicer if the
stringification of `Person` instances could read as valid calls to the
constructor. We can fix that by implementing an `inspect` method on the type.

```js#freshExpect:true
<!-- unexpected-markdown freshExpect:true -->
```js
expect.addType({
name: 'Person',
base: 'object',
identify: function (value) {
return value instanceof Person;
},
inspect: function (person, depth, output, inspect) {
output.text('new Person(')
.append(inspect(person.name, depth))
.text(', ')
.append(inspect(person.age, depth))
.text(')');
}
name: 'Person',
base: 'object',
identify: function(value) {
return value instanceof Person;
},
inspect: function(person, depth, output, inspect) {
output
.text('new Person(')
.append(inspect(person.name, depth))
.text(', ')
.append(inspect(person.age, depth))
.text(')');
}
});
```

Expand Down Expand Up @@ -147,50 +149,58 @@ same depth to the `inspect` function.
Let's say we wanted `Person` instances only to be compared by name and not by
age. Then we need to override the `equal` method:

```js#freshExpect:true
<!-- unexpected-markdown freshExpect:true -->
```js
expect.addType({
name: 'Person',
base: 'object',
identify: function (value) {
return value instanceof Person;
},
inspect: function (person, depth, output, inspect) {
output.text('new Person(')
.append(inspect(person.name, depth))
.text(', ')
.append(inspect(person.age, depth))
.text(')');
},
equal: function (a, b, equal) {
return a === b || equal(a.name, b.name);
}
name: 'Person',
base: 'object',
identify: function(value) {
return value instanceof Person;
},
inspect: function(person, depth, output, inspect) {
output
.text('new Person(')
.append(inspect(person.name, depth))
.text(', ')
.append(inspect(person.age, depth))
.text(')');
},
equal: function(a, b, equal) {
return a === b || equal(a.name, b.name);
}
});
```

This will produce the same output as above, but that means the diff if
wrong. It states that the age should be changed. We can fix that the
following way:

```js#freshExpect:true
<!-- unexpected-markdown freshExpect:true -->
```js
expect.addType({
name: 'Person',
base: 'object',
identify: function (value) {
return value instanceof Person;
},
inspect: function (person, depth, output, inspect) {
output.text('new Person(')
.append(inspect(person.name, depth))
.text(', ')
.append(inspect(person.age, depth))
.text(')');
},
equal: function (a, b, equal) {
return a === b || equal(a.name, b.name);
},
diff: function (actual, expected, output, diff, inspect) {
return this.baseType.diff({name: actual.name}, {name: expected.name}, output);
}
name: 'Person',
base: 'object',
identify: function(value) {
return value instanceof Person;
},
inspect: function(person, depth, output, inspect) {
output
.text('new Person(')
.append(inspect(person.name, depth))
.text(', ')
.append(inspect(person.age, depth))
.text(')');
},
equal: function(a, b, equal) {
return a === b || equal(a.name, b.name);
},
diff: function(actual, expected, output, diff, inspect) {
return this.baseType.diff(
{ name: actual.name },
{ name: expected.name },
output
);
}
});
```

Expand Down Expand Up @@ -218,53 +228,62 @@ on the base directly when you know it is the one you need.

You could also do something really custom as seen below:

```js#freshExpect:true
<!-- unexpected-markdown freshExpect:true -->
```js
var inlineDiff = true; // used to change inlining in a later example

expect.addType({
name: 'Person',
base: 'object',
identify: function (value) {
return value instanceof Person;
},
inspect: function (person, depth, output, inspect) {
output.text('new Person(')
.append(inspect(person.name, depth))
.text(', ')
.append(inspect(person.age, depth))
.text(')');
},
equal: function (a, b, equal) {
return a === b || equal(a.name, b.name);
},
diff: function (actual, expected, output, diff, inspect) {
output.inline = inlineDiff;
var nameDiff = diff(actual.name, expected.name);

output.text('new Person(')
.nl()
.indentLines();

if (nameDiff && nameDiff.inline) {
output.append(nameDiff);
} else {
output.i().append(inspect(actual.name)).text(',').sp()
.annotationBlock(function () {
this.error('should be ').append(inspect(expected.name));
if (nameDiff) {
this.nl().append(nameDiff);
}
})
.nl();
}

output.i().append(inspect(actual.age))
.outdentLines()
.nl()
.text(')');

return output;
name: 'Person',
base: 'object',
identify: function(value) {
return value instanceof Person;
},
inspect: function(person, depth, output, inspect) {
output
.text('new Person(')
.append(inspect(person.name, depth))
.text(', ')
.append(inspect(person.age, depth))
.text(')');
},
equal: function(a, b, equal) {
return a === b || equal(a.name, b.name);
},
diff: function(actual, expected, output, diff, inspect) {
output.inline = inlineDiff;
var nameDiff = diff(actual.name, expected.name);

output
.text('new Person(')
.nl()
.indentLines();

if (nameDiff && nameDiff.inline) {
output.append(nameDiff);
} else {
output
.i()
.append(inspect(actual.name))
.text(',')
.sp()
.annotationBlock(function() {
this.error('should be ').append(inspect(expected.name));
if (nameDiff) {
this.nl().append(nameDiff);
}
})
.nl();
}

output
.i()
.append(inspect(actual.age))
.outdentLines()
.nl()
.text(')');

return output;
}
});
```

Expand Down
14 changes: 8 additions & 6 deletions documentation/api/expect.md
Expand Up @@ -26,9 +26,10 @@ does some unholy trickery so it also works in Jasmine.
Note that if the assertion is asynchronous, you'll have to return the promise
to the `it` block:

```js#eval:false
it('should call the callback', function () {
return expect(setImmediate, 'to call the callback');
<!-- unexpected-markdown evaluate:false -->
```js
it('should call the callback', function() {
return expect(setImmediate, 'to call the callback');
});
```

Expand All @@ -52,8 +53,9 @@ expect('abc', 'to be a string').and('to have length', 3);
Again, note that you need to return the value returned by `expect` to your `it`
block if any of the assertions are asynchronous:

```js#eval:false
it('should do the right thing', function () {
return expect(setImmediate, 'to be a function').and('to call the callback');
<!-- unexpected-markdown evaluate: false -->
```js
it('should do the right thing', function() {
return expect(setImmediate, 'to be a function').and('to call the callback');
});
```