Skip to content

Commit 304f89a

Browse files
Add exemplar analyzers (#116)
* Add exemplar fixtures * Enable exemplar analyzers * Remove fruit-picker from list
1 parent 50a48bf commit 304f89a

File tree

108 files changed

+6211
-2
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

108 files changed

+6211
-2
lines changed

CHANGELOG.md

+21
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,26 @@
11
# Changelog
22

3+
## 0.16.0
4+
5+
- Add exemplary analyzer for `amusement-park`
6+
- Add exemplary analyzer for `bird-watcher`
7+
- Add exemplary analyzer for `coordinate-transformation`
8+
- Add exemplary analyzer for `elyses-analytic-enchantments`
9+
- Add exemplary analyzer for `elyses-destructured-enchantments`
10+
- Add exemplary analyzer for `elyses-enchantments`
11+
- Add exemplary analyzer for `elyses-looping-enchantments`
12+
- Add exemplary analyzer for `elyses-transformative-enchantments`
13+
- Add exemplary analyzer for `factory-sensors`
14+
- Add exemplary analyzer for `high-score-board`
15+
- Add exemplary analyzer for `lasagna-master`
16+
- Add exemplary analyzer for `lucky-numbers`
17+
- Add exemplary analyzer for `mixed-juices`
18+
- Add exemplary analyzer for `nullability`
19+
- Add exemplary analyzer for `ozans-playlist`
20+
- Add exemplary analyzer for `pizza-order`
21+
- Add exemplary analyzer for `translation-service`
22+
- Add exemplary analyzer for `vehicle-purchase`
23+
324
## 0.15.0
425

526
- Allow non-optimal constants in `resistor-color-duo`

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@exercism/javascript-analyzer",
3-
"version": "0.15.0",
3+
"version": "0.16.0",
44
"description": "Exercism analyzer for javascript",
55
"repository": "https://github.com/exercism/javascript-analyzer",
66
"author": "Derk-Jan Karrenbeld <[email protected]>",

src/analyzers/Autoload.ts

+27
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,33 @@ function autoload(exercise: Readonly<Exercise>): ReturnType<NodeRequire> {
4242
path.join(__dirname, 'concept', exercise.slug, 'index'),
4343
]
4444

45+
// These exercises can also defer to the exemplar analyzer only
46+
if (
47+
[
48+
'amusement-park',
49+
'bird-watcher',
50+
'coordinate-transformation',
51+
'elyses-analytic-enchantments',
52+
'elyses-destructured-enchantments',
53+
'elyses-enchantments',
54+
'elyses-looping-enchantments',
55+
'elyses-transformative-enchantments',
56+
'factory-sensors',
57+
// 'fruit-picker',
58+
'high-score-board',
59+
'lasagna-master',
60+
'lucky-numbers',
61+
'mixed-juices',
62+
'nullability',
63+
'ozans-playlist',
64+
'pizza-order',
65+
'translation-service',
66+
'vehicle-purchase',
67+
].includes(exercise.slug)
68+
) {
69+
modulePaths.push(path.join(__dirname, 'concept', '__exemplar', 'index'))
70+
}
71+
4572
const results = modulePaths.map((modulePath) => {
4673
try {
4774
return require(modulePath)

test/analyzers/__exemplar/exemplar.ts

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import { DirectoryWithConfigInput } from '@exercism/static-analysis'
2+
import path from 'path'
3+
import { ExemplarAnalyzer } from '~src/analyzers/concept/__exemplar'
4+
import { EXEMPLAR_SOLUTION } from '~src/comments/shared'
5+
import { makeAnalyze, makeOptions } from '~test/helpers/smoke'
6+
;[
7+
'amusement-park',
8+
'bird-watcher',
9+
'coordinate-transformation',
10+
'elyses-analytic-enchantments',
11+
'elyses-destructured-enchantments',
12+
'elyses-enchantments',
13+
'elyses-looping-enchantments',
14+
'elyses-transformative-enchantments',
15+
'factory-sensors',
16+
// 'fruit-picker',
17+
'high-score-board',
18+
'lasagna-master',
19+
'lucky-numbers',
20+
'mixed-juices',
21+
'nullability',
22+
'ozans-playlist',
23+
'pizza-order',
24+
'translation-service',
25+
'vehicle-purchase',
26+
].forEach((exercise) => {
27+
const inputDir = path.join(
28+
__dirname,
29+
'..',
30+
'..',
31+
'fixtures',
32+
exercise,
33+
'exemplar'
34+
)
35+
36+
const analyze = makeAnalyze(
37+
() => new ExemplarAnalyzer(),
38+
makeOptions({
39+
get inputDir(): string {
40+
return inputDir
41+
},
42+
get exercise(): string {
43+
return exercise
44+
},
45+
})
46+
)
47+
48+
describe(`When running analysis on ${exercise}`, () => {
49+
it('recognises the exemplar solution', async () => {
50+
const input = new DirectoryWithConfigInput(inputDir)
51+
52+
const [solution] = await input.read()
53+
const output = await analyze(solution)
54+
55+
expect(output.comments.length).toBe(1)
56+
expect(output.comments[0].type).toBe('celebratory')
57+
expect(output.comments[0].externalTemplate).toBe(
58+
EXEMPLAR_SOLUTION().externalTemplate
59+
)
60+
})
61+
})
62+
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"blurb": "Learn about undefined and null by managing visitors and tickets at an amusement park.",
3+
"authors": ["junedev"],
4+
"contributors": [],
5+
"files": {
6+
"solution": ["amusement-park.js"],
7+
"test": ["amusement-park.spec.js"],
8+
"exemplar": [".meta/exemplar.js"]
9+
},
10+
"forked_from": ["ruby/amusement-park"]
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/// <reference path="../global.d.ts" />
2+
// @ts-check
3+
4+
/**
5+
* Creates a new visitor.
6+
*
7+
* @param {string} name
8+
* @param {number} age
9+
* @param {string} ticketId
10+
* @returns {Visitor} the visitor that was created
11+
*/
12+
export function createVisitor(name, age, ticketId) {
13+
return { name, age, ticketId };
14+
}
15+
16+
/**
17+
* Revokes a ticket for a visitor.
18+
*
19+
* @param {Visitor} visitor the visitor with an active ticket
20+
* @returns {Visitor} the visitor without a ticket
21+
*/
22+
export function revokeTicket(visitor) {
23+
visitor.ticketId = null;
24+
return visitor;
25+
}
26+
27+
/**
28+
* Determines the status a ticket has in the ticket tracking object.
29+
*
30+
* @param {Record<string, string|null>} tickets
31+
* @param {string} ticketId
32+
* @returns {string} ticket status
33+
*/
34+
export function ticketStatus(tickets, ticketId) {
35+
if (tickets[ticketId] === undefined) {
36+
return 'unknown ticket id';
37+
}
38+
39+
if (tickets[ticketId] === null) {
40+
return 'not sold';
41+
}
42+
43+
return 'sold to ' + tickets[ticketId];
44+
}
45+
46+
/**
47+
* Determines the status a ticket has in the ticket tracking object
48+
* and returns a simplified status message.
49+
*
50+
* @param {Record<string, string|null>} tickets
51+
* @param {string} ticketId
52+
* @returns {string} ticket status
53+
*/
54+
export function simpleTicketStatus(tickets, ticketId) {
55+
return tickets[ticketId] ?? 'invalid ticket !!!';
56+
}
57+
58+
/**
59+
* Determines the version of the GTC that was signed by the visitor.
60+
*
61+
* @param {VisitorWithGtc} visitor
62+
* @returns {string | undefined} version
63+
*/
64+
export function gtcVersion(visitor) {
65+
return visitor.gtc?.version;
66+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/// <reference path="./global.d.ts" />
2+
// @ts-check
3+
4+
/**
5+
* Creates a new visitor.
6+
*
7+
* @param {string} name
8+
* @param {number} age
9+
* @param {string} ticketId
10+
* @returns {Visitor} the visitor that was created
11+
*/
12+
export function createVisitor(name, age, ticketId) {
13+
return { name, age, ticketId };
14+
}
15+
16+
/**
17+
* Revokes a ticket for a visitor.
18+
*
19+
* @param {Visitor} visitor the visitor with an active ticket
20+
* @returns {Visitor} the visitor without a ticket
21+
*/
22+
export function revokeTicket(visitor) {
23+
visitor.ticketId = null;
24+
return visitor;
25+
}
26+
27+
/**
28+
* Determines the status a ticket has in the ticket tracking object.
29+
*
30+
* @param {Record<string, string|null>} tickets
31+
* @param {string} ticketId
32+
* @returns {string} ticket status
33+
*/
34+
export function ticketStatus(tickets, ticketId) {
35+
if (tickets[ticketId] === undefined) {
36+
return 'unknown ticket id';
37+
}
38+
39+
if (tickets[ticketId] === null) {
40+
return 'not sold';
41+
}
42+
43+
return 'sold to ' + tickets[ticketId];
44+
}
45+
46+
/**
47+
* Determines the status a ticket has in the ticket tracking object
48+
* and returns a simplified status message.
49+
*
50+
* @param {Record<string, string|null>} tickets
51+
* @param {string} ticketId
52+
* @returns {string} ticket status
53+
*/
54+
export function simpleTicketStatus(tickets, ticketId) {
55+
return tickets[ticketId] ?? 'invalid ticket !!!';
56+
}
57+
58+
/**
59+
* Determines the version of the GTC that was signed by the visitor.
60+
*
61+
* @param {VisitorWithGtc} visitor
62+
* @returns {string | undefined} version
63+
*/
64+
export function gtcVersion(visitor) {
65+
return visitor.gtc?.version;
66+
}

0 commit comments

Comments
 (0)