From cd2ce616d687f98625e878a9e1555bbb73e7ff3e Mon Sep 17 00:00:00 2001 From: Lucas Azzola Date: Fri, 9 Feb 2018 19:24:03 +1100 Subject: [PATCH 1/3] feat(jest-docblock): support multiple of the same @pragma --- packages/jest-docblock/README.md | 6 +-- .../jest-docblock/src/__tests__/index.test.js | 39 +++++++++++++++++++ packages/jest-docblock/src/index.js | 22 ++++++++--- 3 files changed, 58 insertions(+), 9 deletions(-) diff --git a/packages/jest-docblock/README.md b/packages/jest-docblock/README.md index b3a5bc7b8900..d848f0a855f2 100644 --- a/packages/jest-docblock/README.md +++ b/packages/jest-docblock/README.md @@ -99,17 +99,17 @@ string (`""`). Strips the top docblock from a file and return the result. If a file does not have a docblock at the top, then return the file unchanged. -### `parse(docblock: string): {[key: string]: string}` +### `parse(docblock: string): {[key: string]: string | string[] }` Parses the pragmas in a docblock string into an object whose keys are the pragma tags and whose values are the arguments to those pragmas. -### `parseWithComments(docblock: string): { comments: string, pragmas: {[key: string]: string} }` +### `parseWithComments(docblock: string): { comments: string, pragmas: {[key: string]: string | string[]} }` Similar to `parse` except this method also returns the comments from the docblock. Useful when used with `print()`. -### `print({ comments?: string, pragmas?: {[key: string]: string} }): string` +### `print({ comments?: string, pragmas?: {[key: string]: string | string[]} }): string` Prints an object of key-value pairs back into a docblock. If `comments` are provided, they will be positioned on the top of the docblock. diff --git a/packages/jest-docblock/src/__tests__/index.test.js b/packages/jest-docblock/src/__tests__/index.test.js index d04edfee52e0..380c04212c50 100644 --- a/packages/jest-docblock/src/__tests__/index.test.js +++ b/packages/jest-docblock/src/__tests__/index.test.js @@ -119,6 +119,27 @@ describe('docblock', () => { }); }); + it('parses multiple of the same directives out of a docblock', () => { + const code = + '/**' + + os.EOL + + '' + + ' * @x foo' + + os.EOL + + '' + + ' * @x bar' + + os.EOL + + '' + + ' * @y' + + os.EOL + + '' + + ' */'; + expect(docblock.parse(code)).toEqual({ + x: ['foo', 'bar'], + y: '', + }); + }); + it('parses directives out of a docblock with comments', () => { const code = '/**' + @@ -395,6 +416,24 @@ describe('docblock', () => { ); }); + it('prints docblocks with multiple of the same pragma', () => { + const pragmas = { + x: ['a', 'b'], + y: 'c', + }; + expect(docblock.print({pragmas})).toEqual( + '/**' + + os.EOL + + ' * @x a' + + os.EOL + + ' * @x b' + + os.EOL + + ' * @y c' + + os.EOL + + ' */', + ); + }); + it('prints docblocks with pragmas', () => { const pragmas = { flow: 'foo', diff --git a/packages/jest-docblock/src/index.js b/packages/jest-docblock/src/index.js index a018d843fc4a..e84e3e33b110 100644 --- a/packages/jest-docblock/src/index.js +++ b/packages/jest-docblock/src/index.js @@ -64,7 +64,15 @@ export function parseWithComments( let match; while ((match = propertyRe.exec(docblock))) { // strip linecomments from pragmas - result[match[1]] = match[2].replace(lineCommentRe, ''); + const nextPragma = match[2].replace(lineCommentRe, ''); + if ( + typeof result[match[1]] === 'string' || + Array.isArray(result[match[1]]) + ) { + result[match[1]] = [].concat(result[match[1]], nextPragma); + } else { + result[match[1]] = nextPragma; + } } return {comments, pragmas: result}; } @@ -85,15 +93,17 @@ export function print({ const keys = Object.keys(pragmas); const printedObject = keys - .map(key => start + ' ' + printKeyValue(key, pragmas[key]) + line) + .map(key => printKeyValues(key, pragmas[key])) + .reduce((arr, next) => arr.concat(next), []) + .map(keyValue => start + ' ' + keyValue + line) .join(''); if (!comments) { if (keys.length === 0) { return ''; } - if (keys.length === 1) { - return `${head} ${printKeyValue(keys[0], pragmas[keys[0]])}${tail}`; + if (keys.length === 1 && !Array.isArray(pragmas[keys[0]])) { + return `${head} ${printKeyValues(keys[0], pragmas[keys[0]])}${tail}`; } } @@ -113,6 +123,6 @@ export function print({ ); } -function printKeyValue(key, value) { - return `@${key} ${value}`.trim(); +function printKeyValues(key, valueOrArray) { + return [].concat(valueOrArray).map(value => `@${key} ${value}`.trim()); } From e58ac7f2c7c724ef23bfb47b8180a90721290cd1 Mon Sep 17 00:00:00 2001 From: Lucas Azzola Date: Fri, 9 Feb 2018 19:43:55 +1100 Subject: [PATCH 2/3] chore: fix types --- CHANGELOG.md | 2 ++ .../jest-docblock/src/__tests__/index.test.js | 21 ++++++++++++++++++- packages/jest-docblock/src/index.js | 13 ++++++------ 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c56b24dca680..0081eadcd5c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ * `[babel-jest]` Revert "Remove retainLines from babel-jest" ([#5496](https://github.com/facebook/jest/pull/5496)) +* `[jest-docblock]` Support multiple of the same `@pragma`. + ([#5154](https://github.com/facebook/jest/pull/5502)) ### Features diff --git a/packages/jest-docblock/src/__tests__/index.test.js b/packages/jest-docblock/src/__tests__/index.test.js index 380c04212c50..38ea99797371 100644 --- a/packages/jest-docblock/src/__tests__/index.test.js +++ b/packages/jest-docblock/src/__tests__/index.test.js @@ -140,6 +140,26 @@ describe('docblock', () => { }); }); + it('parses >=3 of the same directives out of a docblock', () => { + const code = + '/**' + + os.EOL + + '' + + ' * @x foo' + + os.EOL + + '' + + ' * @x bar' + + os.EOL + + '' + + ' * @x baz' + + os.EOL + + '' + + ' */'; + expect(docblock.parse(code)).toEqual({ + x: ['foo', 'bar', 'baz'], + }); + }); + it('parses directives out of a docblock with comments', () => { const code = '/**' + @@ -433,7 +453,6 @@ describe('docblock', () => { ' */', ); }); - it('prints docblocks with pragmas', () => { const pragmas = { flow: 'foo', diff --git a/packages/jest-docblock/src/index.js b/packages/jest-docblock/src/index.js index e84e3e33b110..e2740dda1dc9 100644 --- a/packages/jest-docblock/src/index.js +++ b/packages/jest-docblock/src/index.js @@ -10,6 +10,8 @@ import detectNewline from 'detect-newline'; import {EOL} from 'os'; +type Pragmas = {[key: string]: string | string[], __proto__: null}; + const commentEndRe = /\*\/$/; const commentStartRe = /^\/\*\*/; const docblockRe = /^\s*(\/\*\*?(.|\r?\n)*?\*\/)/; @@ -31,15 +33,13 @@ export function strip(contents: string) { return match && match[0] ? contents.substring(match[0].length) : contents; } -export function parse( - docblock: string, -): {[key: string]: string, __proto__: null} { +export function parse(docblock: string): Pragmas { return parseWithComments(docblock).pragmas; } export function parseWithComments( docblock: string, -): {comments: string, pragmas: {[key: string]: string, __proto__: null}} { +): {comments: string, pragmas: Pragmas} { const line = detectNewline(docblock) || EOL; docblock = docblock @@ -82,7 +82,7 @@ export function print({ pragmas = {}, }: { comments?: string, - pragmas?: {[key: string]: string, __proto__: null}, + pragmas?: Pragmas, __proto__: null, }): string { const line = detectNewline(comments) || EOL; @@ -103,7 +103,8 @@ export function print({ return ''; } if (keys.length === 1 && !Array.isArray(pragmas[keys[0]])) { - return `${head} ${printKeyValues(keys[0], pragmas[keys[0]])}${tail}`; + const value = pragmas[keys[0]]; + return `${head} ${printKeyValues(keys[0], value)[0]}${tail}`; } } From 104fc53a4ab35268e9bd7172b800e0b334849b3f Mon Sep 17 00:00:00 2001 From: Lucas Azzola Date: Fri, 9 Feb 2018 20:00:49 +1100 Subject: [PATCH 3/3] fix(jest-haste-map): update to allow multiple pragmas --- packages/jest-haste-map/src/worker.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/jest-haste-map/src/worker.js b/packages/jest-haste-map/src/worker.js index 7c253fe59482..8a835c3a4492 100644 --- a/packages/jest-haste-map/src/worker.js +++ b/packages/jest-haste-map/src/worker.js @@ -37,7 +37,7 @@ export async function worker(data: WorkerMessage): Promise { const filePath = data.filePath; const content = fs.readFileSync(filePath, 'utf8'); let module; - let id; + let id: ?string; let dependencies; if (filePath.endsWith(PACKAGE_JSON)) { @@ -51,7 +51,8 @@ export async function worker(data: WorkerMessage): Promise { id = hasteImpl.getHasteName(filePath); } else { const doc = docblock.parse(docblock.extract(content)); - id = doc.providesModule || doc.provides; + const idPragmas = [].concat(doc.providesModule || doc.provides); + id = idPragmas[0]; } dependencies = extractRequires(content); if (id) {