Skip to content

Commit f2ef92d

Browse files
azzcpojer
authored andcommitted
feat(jest-docblock): support multiple of the same @pragma (#5502)
* feat(jest-docblock): support multiple of the same @pragma * chore: fix types * fix(jest-haste-map): update to allow multiple pragmas
1 parent 97f0308 commit f2ef92d

File tree

5 files changed

+88
-16
lines changed

5 files changed

+88
-16
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
* `[babel-jest]` Revert "Remove retainLines from babel-jest"
66
([#5496](https://github.com/facebook/jest/pull/5496))
7+
* `[jest-docblock]` Support multiple of the same `@pragma`.
8+
([#5154](https://github.com/facebook/jest/pull/5502))
79

810
### Features
911

packages/jest-docblock/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,17 +99,17 @@ string (`""`).
9999
Strips the top docblock from a file and return the result. If a file does not
100100
have a docblock at the top, then return the file unchanged.
101101

102-
### `parse(docblock: string): {[key: string]: string}`
102+
### `parse(docblock: string): {[key: string]: string | string[] }`
103103

104104
Parses the pragmas in a docblock string into an object whose keys are the pragma
105105
tags and whose values are the arguments to those pragmas.
106106

107-
### `parseWithComments(docblock: string): { comments: string, pragmas: {[key: string]: string} }`
107+
### `parseWithComments(docblock: string): { comments: string, pragmas: {[key: string]: string | string[]} }`
108108

109109
Similar to `parse` except this method also returns the comments from the
110110
docblock. Useful when used with `print()`.
111111

112-
### `print({ comments?: string, pragmas?: {[key: string]: string} }): string`
112+
### `print({ comments?: string, pragmas?: {[key: string]: string | string[]} }): string`
113113

114114
Prints an object of key-value pairs back into a docblock. If `comments` are
115115
provided, they will be positioned on the top of the docblock.

packages/jest-docblock/src/__tests__/index.test.js

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,47 @@ describe('docblock', () => {
119119
});
120120
});
121121

122+
it('parses multiple of the same directives out of a docblock', () => {
123+
const code =
124+
'/**' +
125+
os.EOL +
126+
'' +
127+
' * @x foo' +
128+
os.EOL +
129+
'' +
130+
' * @x bar' +
131+
os.EOL +
132+
'' +
133+
' * @y' +
134+
os.EOL +
135+
'' +
136+
' */';
137+
expect(docblock.parse(code)).toEqual({
138+
x: ['foo', 'bar'],
139+
y: '',
140+
});
141+
});
142+
143+
it('parses >=3 of the same directives out of a docblock', () => {
144+
const code =
145+
'/**' +
146+
os.EOL +
147+
'' +
148+
' * @x foo' +
149+
os.EOL +
150+
'' +
151+
' * @x bar' +
152+
os.EOL +
153+
'' +
154+
' * @x baz' +
155+
os.EOL +
156+
'' +
157+
' */';
158+
expect(docblock.parse(code)).toEqual({
159+
x: ['foo', 'bar', 'baz'],
160+
});
161+
});
162+
122163
it('parses directives out of a docblock with comments', () => {
123164
const code =
124165
'/**' +
@@ -395,6 +436,23 @@ describe('docblock', () => {
395436
);
396437
});
397438

439+
it('prints docblocks with multiple of the same pragma', () => {
440+
const pragmas = {
441+
x: ['a', 'b'],
442+
y: 'c',
443+
};
444+
expect(docblock.print({pragmas})).toEqual(
445+
'/**' +
446+
os.EOL +
447+
' * @x a' +
448+
os.EOL +
449+
' * @x b' +
450+
os.EOL +
451+
' * @y c' +
452+
os.EOL +
453+
' */',
454+
);
455+
});
398456
it('prints docblocks with pragmas', () => {
399457
const pragmas = {
400458
flow: 'foo',

packages/jest-docblock/src/index.js

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
import detectNewline from 'detect-newline';
1111
import {EOL} from 'os';
1212

13+
type Pragmas = {[key: string]: string | string[], __proto__: null};
14+
1315
const commentEndRe = /\*\/$/;
1416
const commentStartRe = /^\/\*\*/;
1517
const docblockRe = /^\s*(\/\*\*?(.|\r?\n)*?\*\/)/;
@@ -31,15 +33,13 @@ export function strip(contents: string) {
3133
return match && match[0] ? contents.substring(match[0].length) : contents;
3234
}
3335

34-
export function parse(
35-
docblock: string,
36-
): {[key: string]: string, __proto__: null} {
36+
export function parse(docblock: string): Pragmas {
3737
return parseWithComments(docblock).pragmas;
3838
}
3939

4040
export function parseWithComments(
4141
docblock: string,
42-
): {comments: string, pragmas: {[key: string]: string, __proto__: null}} {
42+
): {comments: string, pragmas: Pragmas} {
4343
const line = detectNewline(docblock) || EOL;
4444

4545
docblock = docblock
@@ -64,7 +64,15 @@ export function parseWithComments(
6464
let match;
6565
while ((match = propertyRe.exec(docblock))) {
6666
// strip linecomments from pragmas
67-
result[match[1]] = match[2].replace(lineCommentRe, '');
67+
const nextPragma = match[2].replace(lineCommentRe, '');
68+
if (
69+
typeof result[match[1]] === 'string' ||
70+
Array.isArray(result[match[1]])
71+
) {
72+
result[match[1]] = [].concat(result[match[1]], nextPragma);
73+
} else {
74+
result[match[1]] = nextPragma;
75+
}
6876
}
6977
return {comments, pragmas: result};
7078
}
@@ -74,7 +82,7 @@ export function print({
7482
pragmas = {},
7583
}: {
7684
comments?: string,
77-
pragmas?: {[key: string]: string, __proto__: null},
85+
pragmas?: Pragmas,
7886
__proto__: null,
7987
}): string {
8088
const line = detectNewline(comments) || EOL;
@@ -85,15 +93,18 @@ export function print({
8593
const keys = Object.keys(pragmas);
8694

8795
const printedObject = keys
88-
.map(key => start + ' ' + printKeyValue(key, pragmas[key]) + line)
96+
.map(key => printKeyValues(key, pragmas[key]))
97+
.reduce((arr, next) => arr.concat(next), [])
98+
.map(keyValue => start + ' ' + keyValue + line)
8999
.join('');
90100

91101
if (!comments) {
92102
if (keys.length === 0) {
93103
return '';
94104
}
95-
if (keys.length === 1) {
96-
return `${head} ${printKeyValue(keys[0], pragmas[keys[0]])}${tail}`;
105+
if (keys.length === 1 && !Array.isArray(pragmas[keys[0]])) {
106+
const value = pragmas[keys[0]];
107+
return `${head} ${printKeyValues(keys[0], value)[0]}${tail}`;
97108
}
98109
}
99110

@@ -113,6 +124,6 @@ export function print({
113124
);
114125
}
115126

116-
function printKeyValue(key, value) {
117-
return `@${key} ${value}`.trim();
127+
function printKeyValues(key, valueOrArray) {
128+
return [].concat(valueOrArray).map(value => `@${key} ${value}`.trim());
118129
}

packages/jest-haste-map/src/worker.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export async function worker(data: WorkerMessage): Promise<WorkerMetadata> {
3737
const filePath = data.filePath;
3838
const content = fs.readFileSync(filePath, 'utf8');
3939
let module;
40-
let id;
40+
let id: ?string;
4141
let dependencies;
4242

4343
if (filePath.endsWith(PACKAGE_JSON)) {
@@ -51,7 +51,8 @@ export async function worker(data: WorkerMessage): Promise<WorkerMetadata> {
5151
id = hasteImpl.getHasteName(filePath);
5252
} else {
5353
const doc = docblock.parse(docblock.extract(content));
54-
id = doc.providesModule || doc.provides;
54+
const idPragmas = [].concat(doc.providesModule || doc.provides);
55+
id = idPragmas[0];
5556
}
5657
dependencies = extractRequires(content);
5758
if (id) {

0 commit comments

Comments
 (0)