From 34149aa97dd75584615a69dbc748efc8a1ad7385 Mon Sep 17 00:00:00 2001 From: atanasster Date: Sat, 22 Feb 2020 21:21:38 -0500 Subject: [PATCH] fix: support for arg usage with assignment --- blocks/core/src/Source/argument-utils.ts | 20 +- .../src/babel/control-values-in-source.ts | 31 +- .../prop-usage-locations.test.js.snap | 303 ++++++++++++------ .../test/prop-usage-locations.test.js | 8 + core/specification/src/stories.ts | 19 +- 5 files changed, 273 insertions(+), 108 deletions(-) diff --git a/blocks/core/src/Source/argument-utils.ts b/blocks/core/src/Source/argument-utils.ts index df31e3102..fa8cb336f 100644 --- a/blocks/core/src/Source/argument-utils.ts +++ b/blocks/core/src/Source/argument-utils.ts @@ -2,7 +2,7 @@ import jsStringEscape from 'js-string-escape'; import { ControlTypes, StoryArguments, - CodeLocation, + ArgUsageLocation, } from '@component-controls/specification'; import { LoadedComponentControl, @@ -20,7 +20,7 @@ export const getArgumentNames = (args: StoryArguments): string[] => { interface UsageProp { name: string; - loc: CodeLocation; + loc: ArgUsageLocation; } export const getArgumentsUsage = (args: StoryArguments): UsageProp[] => { return args.reduce((acc: any, a) => { @@ -56,18 +56,24 @@ export const mergeControlValues = ( //sort locations in reverse order, so to replace source backwards locations .sort((a, b) => { - if (a.loc.start.line === b.loc.start.line) { - return b.loc.start.column - a.loc.start.column; + if (a.loc.loc.start.line === b.loc.loc.start.line) { + return b.loc.loc.start.column - a.loc.loc.start.column; } - return b.loc.start.line - a.loc.start.line; + return b.loc.loc.start.line - a.loc.loc.start.line; }) .forEach(l => { - const { start, end } = l.loc; + const { start, end } = l.loc.loc; const val: LoadedComponentControl = controls[l.name]; if (val && val.value !== val.defaultValue) { const value: any = val.value; - const strValue: string = + let strValue: string = val.type === ControlTypes.TEXT ? `"${jsStringEscape(value)}"` : value; + console.log(l); + if (l.loc.name) { + if (l.loc.name.name === l.name) { + strValue = `${l.loc.name.name}: ${strValue}`; + } + } if (start.line === end.line) { lines[start.line] = replaceString( lines[start.line], diff --git a/core/instrument/src/babel/control-values-in-source.ts b/core/instrument/src/babel/control-values-in-source.ts index daca66c57..10b0b544b 100644 --- a/core/instrument/src/babel/control-values-in-source.ts +++ b/core/instrument/src/babel/control-values-in-source.ts @@ -2,6 +2,7 @@ import { Story, StoryArguments, StoryArgument, + ArgUsageLocation, } from '@component-controls/specification'; import { adjustSourceLocation } from './utils'; @@ -30,20 +31,46 @@ export const addArgumentUsage = ( story: Story, args: StoryArguments, node: any, -) => { +): ArgUsageLocation | undefined => { const param = findArguments(args, node.name); if (param) { if (param.usage === undefined) { param.usage = []; } - param.usage.push(adjustSourceLocation(story, node.loc)); + const loc = adjustSourceLocation(story, node.loc); + const existing = param.usage.find( + p => + p.loc.start.line === loc.start.line && + p.loc.start.column === loc.start.column && + p.loc.end.line === loc.end.line && + p.loc.end.column === loc.end.column, + ); + const usage: ArgUsageLocation = { loc }; + if (!existing) { + param.usage.push(usage); + return usage; + } } + return undefined; }; export const extractArgumentsUsage = (story: Story, args: StoryArguments) => { return { Identifier: (path: any) => { addArgumentUsage(story, args, path.node); }, + Property: (path: any) => { + const node = path.node; + if (node.value.type === 'Identifier' && node.key.type === 'Identifier') { + const usage = addArgumentUsage(story, args, node.value); + if (usage) { + usage.name = { + loc: adjustSourceLocation(story, node.key.loc), + name: node.key.name, + }; + path.skip(); + } + } + }, }; }; diff --git a/core/instrument/test/__snapshots__/prop-usage-locations.test.js.snap b/core/instrument/test/__snapshots__/prop-usage-locations.test.js.snap index 2994695e0..3c387d5e1 100644 --- a/core/instrument/test/__snapshots__/prop-usage-locations.test.js.snap +++ b/core/instrument/test/__snapshots__/prop-usage-locations.test.js.snap @@ -45,13 +45,15 @@ Object { "name": "first", "usage": Array [ Object { - "end": Object { - "column": 29, - "line": 2, - }, - "start": Object { - "column": 24, - "line": 2, + "loc": Object { + "end": Object { + "column": 29, + "line": 2, + }, + "start": Object { + "column": 24, + "line": 2, + }, }, }, ], @@ -71,13 +73,15 @@ Object { "name": "last", "usage": Array [ Object { - "end": Object { - "column": 41, - "line": 2, - }, - "start": Object { - "column": 37, - "line": 2, + "loc": Object { + "end": Object { + "column": 41, + "line": 2, + }, + "start": Object { + "column": 37, + "line": 2, + }, }, }, ], @@ -99,13 +103,15 @@ Object { "name": "age", "usage": Array [ Object { - "end": Object { - "column": 25, - "line": 3, - }, - "start": Object { - "column": 22, - "line": 3, + "loc": Object { + "end": Object { + "column": 25, + "line": 3, + }, + "start": Object { + "column": 22, + "line": 3, + }, }, }, ], @@ -171,13 +177,15 @@ Object { "name": "props", "usage": Array [ Object { - "end": Object { - "column": 18, - "line": 2, - }, - "start": Object { - "column": 13, - "line": 2, + "loc": Object { + "end": Object { + "column": 18, + "line": 2, + }, + "start": Object { + "column": 13, + "line": 2, + }, }, }, ], @@ -238,13 +246,15 @@ Object { "name": "name", "usage": Array [ Object { - "end": Object { - "column": 18, - "line": 0, - }, - "start": Object { - "column": 14, - "line": 0, + "loc": Object { + "end": Object { + "column": 18, + "line": 0, + }, + "start": Object { + "column": 14, + "line": 0, + }, }, }, ], @@ -270,6 +280,85 @@ Object { } `; +exports[`prop-usage-locations expression usage 1`] = ` +Object { + "stories": Object { + "selectProp": Object { + "arguments": Array [ + Object { + "loc": Object { + "end": Object { + "column": 10, + "line": 0, + }, + "start": Object { + "column": 1, + "line": 0, + }, + }, + "name": undefined, + "value": Array [ + Object { + "loc": Object { + "end": Object { + "column": 8, + "line": 0, + }, + "start": Object { + "column": 3, + "line": 0, + }, + }, + "name": "value", + "usage": Array [ + Object { + "loc": Object { + "end": Object { + "column": 43, + "line": 0, + }, + "start": Object { + "column": 38, + "line": 0, + }, + }, + "name": Object { + "loc": Object { + "end": Object { + "column": 43, + "line": 0, + }, + "start": Object { + "column": 38, + "line": 0, + }, + }, + "name": "value", + }, + }, + ], + "value": "value", + }, + ], + }, + ], + "location": Object { + "end": Object { + "column": 88, + "line": 1, + }, + "start": Object { + "column": 26, + "line": 1, + }, + }, + "name": "selectProp", + "source": "({ value }) =>
{JSON.stringify({ value }, null, 2)}
;", + }, + }, +} +`; + exports[`prop-usage-locations multiple usage 1`] = ` Object { "stories": Object { @@ -302,23 +391,27 @@ Object { "name": "age", "usage": Array [ Object { - "end": Object { - "column": 37, - "line": 2, - }, - "start": Object { - "column": 34, - "line": 2, + "loc": Object { + "end": Object { + "column": 37, + "line": 2, + }, + "start": Object { + "column": 34, + "line": 2, + }, }, }, Object { - "end": Object { - "column": 25, - "line": 3, - }, - "start": Object { - "column": 22, - "line": 3, + "loc": Object { + "end": Object { + "column": 25, + "line": 3, + }, + "start": Object { + "column": 22, + "line": 3, + }, }, }, ], @@ -368,13 +461,15 @@ Object { "name": "props", "usage": Array [ Object { - "end": Object { - "column": 25, - "line": 0, - }, - "start": Object { - "column": 20, - "line": 0, + "loc": Object { + "end": Object { + "column": 25, + "line": 0, + }, + "start": Object { + "column": 20, + "line": 0, + }, }, }, ], @@ -430,13 +525,15 @@ Object { "name": "text", "usage": Array [ Object { - "end": Object { - "column": 21, - "line": 0, - }, - "start": Object { - "column": 17, - "line": 0, + "loc": Object { + "end": Object { + "column": 21, + "line": 0, + }, + "start": Object { + "column": 17, + "line": 0, + }, }, }, ], @@ -481,13 +578,15 @@ Object { "name": "props", "usage": Array [ Object { - "end": Object { - "column": 36, - "line": 0, - }, - "start": Object { - "column": 31, - "line": 0, + "loc": Object { + "end": Object { + "column": 36, + "line": 0, + }, + "start": Object { + "column": 31, + "line": 0, + }, }, }, ], @@ -557,13 +656,15 @@ Object { "name": "name", "usage": Array [ Object { - "end": Object { - "column": 46, - "line": 0, - }, - "start": Object { - "column": 40, - "line": 0, + "loc": Object { + "end": Object { + "column": 46, + "line": 0, + }, + "start": Object { + "column": 40, + "line": 0, + }, }, }, ], @@ -583,13 +684,15 @@ Object { "name": "age", "usage": Array [ Object { - "end": Object { - "column": 56, - "line": 0, - }, - "start": Object { - "column": 53, - "line": 0, + "loc": Object { + "end": Object { + "column": 56, + "line": 0, + }, + "start": Object { + "column": 53, + "line": 0, + }, }, }, ], @@ -647,13 +750,15 @@ Object { "name": "name", "usage": Array [ Object { - "end": Object { - "column": 36, - "line": 0, - }, - "start": Object { - "column": 32, - "line": 0, + "loc": Object { + "end": Object { + "column": 36, + "line": 0, + }, + "start": Object { + "column": 32, + "line": 0, + }, }, }, ], @@ -673,13 +778,15 @@ Object { "name": "age", "usage": Array [ Object { - "end": Object { - "column": 46, - "line": 0, - }, - "start": Object { - "column": 43, - "line": 0, + "loc": Object { + "end": Object { + "column": 46, + "line": 0, + }, + "start": Object { + "column": 43, + "line": 0, + }, }, }, ], diff --git a/core/instrument/test/prop-usage-locations.test.js b/core/instrument/test/prop-usage-locations.test.js index 77c635d07..594e32ffd 100644 --- a/core/instrument/test/prop-usage-locations.test.js +++ b/core/instrument/test/prop-usage-locations.test.js @@ -84,4 +84,12 @@ describe('prop-usage-locations', () => { await parseCSF('export const story = ({ name }) => name;'), ).toMatchSnapshot(); }); + + it('expression usage', async () => { + await expect( + await parseCSF( + 'export const selectProp = ({ value }) =>
{JSON.stringify({ value }, null, 2)}
;', + ), + ).toMatchSnapshot(); + }); }); diff --git a/core/specification/src/stories.ts b/core/specification/src/stories.ts index 4af035866..f1d297ef9 100644 --- a/core/specification/src/stories.ts +++ b/core/specification/src/stories.ts @@ -17,6 +17,23 @@ export interface CodeLocation { start: CodePosition; end: CodePosition; } +export interface ArgUsageLocation { + /** + * where in the story source code is the argument used + * code location is relative to the start of the story + */ + loc: CodeLocation; + + /** + * optional name for the usage of the argument + * example: export const story = ({ value }) => ; + * in this example the name will be 'age' + */ + name?: { + name: string; + loc: CodeLocation; + }; +} /** * arguments passed to the 'story' as extracted by an AST loader @@ -38,7 +55,7 @@ export interface StoryArgument { /** * list of locations where the argument is used in the body of the story */ - usage?: CodeLocation[]; + usage?: ArgUsageLocation[]; } /**