diff --git a/src/lib/operations.test.ts b/src/lib/operations.test.ts index ccb4ba288..985557be2 100644 --- a/src/lib/operations.test.ts +++ b/src/lib/operations.test.ts @@ -27,12 +27,31 @@ function userCall(name: string): Operation { sourceRange: defaultSourceRange(), } } + function userReturn(): Operation { return { type: 'GroupEnd', } } +function moduleBegin(name: string): Operation { + return { + type: 'GroupBegin', + group: { + type: 'ModuleInstance', + name, + moduleId: 0, + }, + sourceRange: defaultSourceRange(), + } +} + +function moduleEnd(): Operation { + return { + type: 'GroupEnd', + } +} + describe('operations filtering', () => { it('drops stdlib operations inside a user-defined function call', async () => { const operations = [ @@ -65,6 +84,25 @@ describe('operations filtering', () => { const actual = filterOperations(operations) expect(actual).toEqual([stdlib('std1'), stdlib('std2'), stdlib('std3')]) }) + it('does not drop module instances that contain no operations', async () => { + const operations = [ + stdlib('std1'), + moduleBegin('foo'), + moduleEnd(), + stdlib('std2'), + moduleBegin('bar'), + moduleEnd(), + stdlib('std3'), + ] + const actual = filterOperations(operations) + expect(actual).toEqual([ + stdlib('std1'), + moduleBegin('foo'), + stdlib('std2'), + moduleBegin('bar'), + stdlib('std3'), + ]) + }) it('preserves user-defined function calls at the end of the list', async () => { const operations = [stdlib('std1'), userCall('foo')] const actual = filterOperations(operations) diff --git a/src/lib/operations.ts b/src/lib/operations.ts index bb4e70d47..9d067c95a 100644 --- a/src/lib/operations.ts +++ b/src/lib/operations.ts @@ -1168,7 +1168,7 @@ export function filterOperations(operations: Operation[]): Operation[] { * for use in the feature tree UI */ const operationFilters = [ - isNotGroupWithNoOperations, + isNotUserFunctionWithNoOperations, isNotInsideGroup, isNotGroupEnd, ] @@ -1202,22 +1202,28 @@ function isNotInsideGroup(operations: Operation[]): Operation[] { /** * A filter to exclude GroupBegin operations and their corresponding GroupEnd - * that don't have any operations inside them from a list of operations. + * that don't have any operations inside them from a list of operations, if it's + * a function call. */ -function isNotGroupWithNoOperations(operations: Operation[]): Operation[] { +function isNotUserFunctionWithNoOperations( + operations: Operation[] +): Operation[] { return operations.filter((op, index) => { if ( op.type === 'GroupBegin' && - // If this is a begin at the end of the array, it's preserved. + op.group.type === 'FunctionCall' && + // If this is a "begin" at the end of the array, it's preserved. index < operations.length - 1 && operations[index + 1].type === 'GroupEnd' ) return false + const previousOp = index > 0 ? operations[index - 1] : undefined if ( op.type === 'GroupEnd' && - // If this is an end at the beginning of the array, it's preserved. - index > 0 && - operations[index - 1].type === 'GroupBegin' + // If this is an "end" at the beginning of the array, it's preserved. + previousOp !== undefined && + previousOp.type === 'GroupBegin' && + previousOp.group.type === 'FunctionCall' ) return false