From 3d05f12073dc2d525055987283eb7c6c6f0196c4 Mon Sep 17 00:00:00 2001 From: Suchita Doshi Date: Wed, 7 Apr 2021 10:22:16 -0700 Subject: [PATCH 1/6] failing parent defintion case --- test/__snapshots__/integration-test.ts.snap | 33 ++++++++ test/integration-test.ts | 88 +++++++++++++++++++++ 2 files changed, 121 insertions(+) diff --git a/test/__snapshots__/integration-test.ts.snap b/test/__snapshots__/integration-test.ts.snap index 12d7d1a2..83f17f10 100644 --- a/test/__snapshots__/integration-test.ts.snap +++ b/test/__snapshots__/integration-test.ts.snap @@ -2635,6 +2635,39 @@ Object { } `; +exports[`integration Go to definition works for all supported cases support parent project addon calling another parent project addon 1`] = ` +Object { + "addonsMeta": Array [ + Object { + "name": "biz", + "root": "lib/biz", + }, + Object { + "name": "box", + "root": "../lib/box", + }, + Object { + "name": "foo", + "root": "../lib/foo", + }, + ], + "registry": Object { + "component": Object { + "bar": Array [ + "../lib/foo/addon/components/bar.js", + "lib/biz/addon/components/bar.js", + ], + }, + "routePath": Object { + "hello": Array [ + "app/templates/hello.hbs", + ], + }, + }, + "response": Array [], +} +`; + exports[`integration Go to definition works for all supported cases to children route from application outlet 1`] = ` Object { "addonsMeta": Array [], diff --git a/test/integration-test.ts b/test/integration-test.ts index 4d2d8045..309b571c 100644 --- a/test/integration-test.ts +++ b/test/integration-test.ts @@ -364,6 +364,94 @@ describe('integration', function () { expect(result).toMatchSnapshot(); }); + it('support parent project addon calling another parent project addon', async () => { + jest.setTimeout(15000); + const result = await getResult( + DefinitionRequest.method, + connection, + { + 'full-project': { + 'app/templates/hello.hbs': '', + lib: { + biz: { + 'addon/components/bar.js': '', + 'package.json': JSON.stringify({ + name: 'biz', + keywords: ['ember-addon'], + dependencies: {}, + 'ember-addon': { + paths: ['../../../lib/foo', '../../../lib/box'], + }, + }), + 'index.js': `/* eslint-env node */ + 'use strict'; + + module.exports = { + name: 'biz', + + isDevelopingAddon() { + return true; + } + };`, + }, + }, + 'package.json': JSON.stringify({ + dependencies: { 'ember-holy-futuristic-template-namespacing-batman': '^1.0.2' }, + 'ember-addon': { + paths: ['lib/biz'], + }, + }), + }, + lib: { + foo: { + addon: { + 'components/bar.js': 'import Boo from "box/components/bar"', + }, + 'package.json': JSON.stringify({ + name: 'foo', + keywords: ['ember-addon'], + dependencies: {}, + }), + 'index.js': `/* eslint-env node */ + 'use strict'; + + module.exports = { + name: 'foo', + + isDevelopingAddon() { + return true; + } + };`, + }, + box: { + addon: { + 'components/bar/js': '', + }, + 'package.json': JSON.stringify({ + name: 'box', + keywords: ['ember-addon'], + dependencies: {}, + }), + 'index.js': `/* eslint-env node */ + 'use strict'; + + module.exports = { + name: 'box', + + isDevelopingAddon() { + return true; + } + };`, + }, + }, + }, + '../lib/foo/addon/components/bar.js', + { line: 0, character: 8 }, + 'full-project' + ); + + expect(result).toMatchSnapshot(); + }); it('go to definition from handlebars template working if we have test for component', async () => { const result = await getResult( DefinitionRequest.method, From 62b0b727454abf9b36ed06a43d63adeb159fe7fc Mon Sep 17 00:00:00 2001 From: Suchita Doshi Date: Wed, 7 Apr 2021 10:33:48 -0700 Subject: [PATCH 2/6] failing parent to child defintion case --- test/__snapshots__/integration-test.ts.snap | 39 +++++++++++++++++++++ test/integration-test.ts | 7 ++-- 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/test/__snapshots__/integration-test.ts.snap b/test/__snapshots__/integration-test.ts.snap index 83f17f10..a5f60655 100644 --- a/test/__snapshots__/integration-test.ts.snap +++ b/test/__snapshots__/integration-test.ts.snap @@ -2668,6 +2668,45 @@ Object { } `; +exports[`integration Go to definition works for all supported cases support parent project addon calling child project 1`] = ` +Object { + "addonsMeta": Array [ + Object { + "name": "biz", + "root": "lib/biz", + }, + Object { + "name": "box", + "root": "../lib/box", + }, + Object { + "name": "foo", + "root": "../lib/foo", + }, + ], + "registry": Object { + "component": Object { + "bar": Array [ + "../lib/foo/addon/components/bar.js", + "lib/biz/addon/components/bar.js", + "../lib/box/addon/components/bar.js", + ], + }, + "helper": Object { + "blah": Array [ + "tests/helpers/blah.js", + ], + }, + "routePath": Object { + "hello": Array [ + "app/templates/hello.hbs", + ], + }, + }, + "response": Array [], +} +`; + exports[`integration Go to definition works for all supported cases to children route from application outlet 1`] = ` Object { "addonsMeta": Array [], diff --git a/test/integration-test.ts b/test/integration-test.ts index 309b571c..2f7c83fc 100644 --- a/test/integration-test.ts +++ b/test/integration-test.ts @@ -364,7 +364,7 @@ describe('integration', function () { expect(result).toMatchSnapshot(); }); - it('support parent project addon calling another parent project addon', async () => { + it('support parent project addon calling child project', async () => { jest.setTimeout(15000); const result = await getResult( DefinitionRequest.method, @@ -372,6 +372,7 @@ describe('integration', function () { { 'full-project': { 'app/templates/hello.hbs': '', + 'tests/helpers/blah.js': '', lib: { biz: { 'addon/components/bar.js': '', @@ -405,7 +406,7 @@ describe('integration', function () { lib: { foo: { addon: { - 'components/bar.js': 'import Boo from "box/components/bar"', + 'components/bar.js': 'import Blah from "full-project/tests/helpers/blah"', }, 'package.json': JSON.stringify({ name: 'foo', @@ -425,7 +426,7 @@ describe('integration', function () { }, box: { addon: { - 'components/bar/js': '', + 'components/bar.js': '', }, 'package.json': JSON.stringify({ name: 'box', From 51e53b9f0fcf740e20eef363d5fc7532d4c790ba Mon Sep 17 00:00:00 2001 From: Suchita Doshi Date: Wed, 7 Apr 2021 10:43:32 -0700 Subject: [PATCH 3/6] update snapshot --- test/__snapshots__/integration-test.ts.snap | 33 --------------------- 1 file changed, 33 deletions(-) diff --git a/test/__snapshots__/integration-test.ts.snap b/test/__snapshots__/integration-test.ts.snap index a5f60655..5411d745 100644 --- a/test/__snapshots__/integration-test.ts.snap +++ b/test/__snapshots__/integration-test.ts.snap @@ -2635,39 +2635,6 @@ Object { } `; -exports[`integration Go to definition works for all supported cases support parent project addon calling another parent project addon 1`] = ` -Object { - "addonsMeta": Array [ - Object { - "name": "biz", - "root": "lib/biz", - }, - Object { - "name": "box", - "root": "../lib/box", - }, - Object { - "name": "foo", - "root": "../lib/foo", - }, - ], - "registry": Object { - "component": Object { - "bar": Array [ - "../lib/foo/addon/components/bar.js", - "lib/biz/addon/components/bar.js", - ], - }, - "routePath": Object { - "hello": Array [ - "app/templates/hello.hbs", - ], - }, - }, - "response": Array [], -} -`; - exports[`integration Go to definition works for all supported cases support parent project addon calling child project 1`] = ` Object { "addonsMeta": Array [ From a36d1a50140a1b568cc3b2cd19e42ddbd1de19eb Mon Sep 17 00:00:00 2001 From: Suchita Doshi Date: Sun, 11 Apr 2021 17:46:22 -0700 Subject: [PATCH 4/6] add support for test definitions and parent to child imports --- .../core/script-definition-provider.ts | 27 +++- test/__snapshots__/integration-test.ts.snap | 87 ++++++----- test/integration-test.ts | 142 +++++++----------- 3 files changed, 124 insertions(+), 132 deletions(-) diff --git a/src/builtin-addons/core/script-definition-provider.ts b/src/builtin-addons/core/script-definition-provider.ts index 6e65ca35..458da71d 100644 --- a/src/builtin-addons/core/script-definition-provider.ts +++ b/src/builtin-addons/core/script-definition-provider.ts @@ -14,7 +14,7 @@ import { isImportSpecifier, } from './../../utils/ast-helpers'; import { normalizeServiceName } from '../../utils/normalizers'; -import { isModuleUnificationApp, podModulePrefixForRoot } from './../../utils/layout-helpers'; +import { getPackageJSON, isModuleUnificationApp, podModulePrefixForRoot } from './../../utils/layout-helpers'; import { provideRouteDefinition } from './template-definition-provider'; import { logInfo } from '../../utils/logger'; @@ -72,9 +72,18 @@ class PathResolvers { const pathParts = pathName.split('/'); pathParts.shift(); - const appParams = [root, 'app', ...pathParts]; + const mayBePathParams = [ + [root, 'app', ...pathParts], + [root, 'tests', ...pathParts], + ]; - return joinPaths(...appParams); + let maybePaths: string[] = []; + + mayBePathParams.forEach((item) => { + maybePaths = maybePaths.concat(joinPaths(...item)); + }); + + return maybePaths; } muImportPaths(root: string, pathName: string) { const pathParts = pathName.split('/'); @@ -185,9 +194,19 @@ export default class CoreScriptDefinitionProvider { } else if (isImportSpecifier(astPath)) { logInfo(`Handle script import for Project "${project.name}"`); const pathName: string = ((astPath.parentFromLevel(2) as unknown) as t.ImportDeclaration).source.value; + const pathPaths = pathName.split('/'); + const maybeAppName = pathPaths.shift(); project.roots.forEach((projectRoot) => { - const potentialPaths = this.guessPathForImport(projectRoot, uri, pathName) || []; + const pkg = getPackageJSON(projectRoot); + let potentialPaths: Location[]; + + // If the start of the pathname is same as the project name, then use that as the root. + if (pkg.name === maybeAppName) { + potentialPaths = this.guessPathForImport(projectRoot, uri, pathPaths.join('/')) || []; + } else { + potentialPaths = this.guessPathForImport(projectRoot, uri, pathName) || []; + } definitions = definitions.concat(potentialPaths); }); diff --git a/test/__snapshots__/integration-test.ts.snap b/test/__snapshots__/integration-test.ts.snap index 5411d745..7a9a0cb6 100644 --- a/test/__snapshots__/integration-test.ts.snap +++ b/test/__snapshots__/integration-test.ts.snap @@ -2635,45 +2635,6 @@ Object { } `; -exports[`integration Go to definition works for all supported cases support parent project addon calling child project 1`] = ` -Object { - "addonsMeta": Array [ - Object { - "name": "biz", - "root": "lib/biz", - }, - Object { - "name": "box", - "root": "../lib/box", - }, - Object { - "name": "foo", - "root": "../lib/foo", - }, - ], - "registry": Object { - "component": Object { - "bar": Array [ - "../lib/foo/addon/components/bar.js", - "lib/biz/addon/components/bar.js", - "../lib/box/addon/components/bar.js", - ], - }, - "helper": Object { - "blah": Array [ - "tests/helpers/blah.js", - ], - }, - "routePath": Object { - "hello": Array [ - "app/templates/hello.hbs", - ], - }, - }, - "response": Array [], -} -`; - exports[`integration Go to definition works for all supported cases to children route from application outlet 1`] = ` Object { "addonsMeta": Array [], @@ -2837,6 +2798,54 @@ Object { } `; +exports[`integration Project class resolution, based on fs path and file structure support parent project addon calling child project 1`] = ` +Object { + "addonsMeta": Array [ + Object { + "name": "biz", + "root": "lib/biz", + }, + Object { + "name": "foo", + "root": "../lib/foo", + }, + ], + "registry": Object { + "component": Object { + "bar": Array [ + "../lib/foo/addon/components/bar.js", + "lib/biz/addon/components/bar.js", + ], + }, + "helper": Object { + "blah": Array [ + "tests/helpers/blah.js", + ], + }, + "routePath": Object { + "hello": Array [ + "app/templates/hello.hbs", + ], + }, + }, + "response": Array [ + Object { + "range": Object { + "end": Object { + "character": 0, + "line": 0, + }, + "start": Object { + "character": 0, + "line": 0, + }, + }, + "uri": "/tests/helpers/blah.js", + }, + ], +} +`; + exports[`integration autocomplete works for angle component slots 1`] = ` Array [ Object { diff --git a/test/integration-test.ts b/test/integration-test.ts index 2f7c83fc..27284ada 100644 --- a/test/integration-test.ts +++ b/test/integration-test.ts @@ -364,95 +364,6 @@ describe('integration', function () { expect(result).toMatchSnapshot(); }); - it('support parent project addon calling child project', async () => { - jest.setTimeout(15000); - const result = await getResult( - DefinitionRequest.method, - connection, - { - 'full-project': { - 'app/templates/hello.hbs': '', - 'tests/helpers/blah.js': '', - lib: { - biz: { - 'addon/components/bar.js': '', - 'package.json': JSON.stringify({ - name: 'biz', - keywords: ['ember-addon'], - dependencies: {}, - 'ember-addon': { - paths: ['../../../lib/foo', '../../../lib/box'], - }, - }), - 'index.js': `/* eslint-env node */ - 'use strict'; - - module.exports = { - name: 'biz', - - isDevelopingAddon() { - return true; - } - };`, - }, - }, - 'package.json': JSON.stringify({ - dependencies: { 'ember-holy-futuristic-template-namespacing-batman': '^1.0.2' }, - 'ember-addon': { - paths: ['lib/biz'], - }, - }), - }, - lib: { - foo: { - addon: { - 'components/bar.js': 'import Blah from "full-project/tests/helpers/blah"', - }, - 'package.json': JSON.stringify({ - name: 'foo', - keywords: ['ember-addon'], - dependencies: {}, - }), - 'index.js': `/* eslint-env node */ - 'use strict'; - - module.exports = { - name: 'foo', - - isDevelopingAddon() { - return true; - } - };`, - }, - box: { - addon: { - 'components/bar.js': '', - }, - 'package.json': JSON.stringify({ - name: 'box', - keywords: ['ember-addon'], - dependencies: {}, - }), - 'index.js': `/* eslint-env node */ - 'use strict'; - - module.exports = { - name: 'box', - - isDevelopingAddon() { - return true; - } - };`, - }, - }, - }, - '../lib/foo/addon/components/bar.js', - { line: 0, character: 8 }, - 'full-project' - ); - - expect(result).toMatchSnapshot(); - }); it('go to definition from handlebars template working if we have test for component', async () => { const result = await getResult( DefinitionRequest.method, @@ -1680,6 +1591,59 @@ describe('integration', function () { expect(result.length).toBe(2); expect(result[0].response.length).toBe(3); }); + + it('support parent project addon calling child project', async () => { + jest.setTimeout(15000); + const result = await getResult( + DefinitionRequest.method, + connection, + { + 'full-project': { + 'app/templates/hello.hbs': '', + 'tests/helpers/blah.js': '', + lib: { + biz: { + 'addon/components/bar.js': '', + 'package.json': JSON.stringify({ + name: 'biz', + keywords: ['ember-addon'], + dependencies: {}, + 'ember-addon': { + paths: ['../../../lib/foo'], + }, + }), + 'index.js': '', + }, + }, + 'package.json': JSON.stringify({ + name: 'full-project', + dependencies: { 'ember-holy-futuristic-template-namespacing-batman': '^1.0.2' }, + 'ember-addon': { + paths: ['lib/biz'], + }, + }), + }, + lib: { + foo: { + addon: { + 'components/bar.js': 'import Blah from "full-project/tests/helpers/blah"', + }, + 'package.json': JSON.stringify({ + name: 'foo', + keywords: ['ember-addon'], + dependencies: {}, + }), + 'index.js': '', + }, + }, + }, + 'lib/foo/addon/components/bar.js', + { line: 0, character: 8 }, + 'full-project' + ); + + expect(result).toMatchSnapshot(); + }); }); describe('Autocomplete works for broken templates', () => { From 7f5f9f71f0aaadca1ba4284ff2d02100240918e5 Mon Sep 17 00:00:00 2001 From: Suchita Doshi Date: Mon, 12 Apr 2021 10:15:36 -0700 Subject: [PATCH 5/6] address comments --- .../core/script-definition-provider.ts | 49 ++++++++++--------- test/integration-test.ts | 1 - 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/builtin-addons/core/script-definition-provider.ts b/src/builtin-addons/core/script-definition-provider.ts index 458da71d..b438871a 100644 --- a/src/builtin-addons/core/script-definition-provider.ts +++ b/src/builtin-addons/core/script-definition-provider.ts @@ -14,7 +14,7 @@ import { isImportSpecifier, } from './../../utils/ast-helpers'; import { normalizeServiceName } from '../../utils/normalizers'; -import { getPackageJSON, isModuleUnificationApp, podModulePrefixForRoot } from './../../utils/layout-helpers'; +import { isModuleUnificationApp, podModulePrefixForRoot } from './../../utils/layout-helpers'; import { provideRouteDefinition } from './template-definition-provider'; import { logInfo } from '../../utils/logger'; @@ -72,19 +72,15 @@ class PathResolvers { const pathParts = pathName.split('/'); pathParts.shift(); - const mayBePathParams = [ - [root, 'app', ...pathParts], - [root, 'tests', ...pathParts], - ]; + const appParams = [root, 'app', ...pathParts]; - let maybePaths: string[] = []; - - mayBePathParams.forEach((item) => { - maybePaths = maybePaths.concat(joinPaths(...item)); - }); + return joinPaths(...appParams); + } - return maybePaths; + resolveTestScopeImport(root: string, pathName: string) { + return joinPaths(path.join(root, pathName)); } + muImportPaths(root: string, pathName: string) { const pathParts = pathName.split('/'); @@ -122,6 +118,10 @@ export default class CoreScriptDefinitionProvider { guessedPaths.push(pathLocation); }); + this.resolvers.resolveTestScopeImport(root, importPath).forEach((pathLocation: string) => { + guessedPaths.push(pathLocation); + }); + return pathsToLocations(...guessedPaths); } guessPathsForType(root: string, fnName: ItemType, typeName: string) { @@ -194,22 +194,23 @@ export default class CoreScriptDefinitionProvider { } else if (isImportSpecifier(astPath)) { logInfo(`Handle script import for Project "${project.name}"`); const pathName: string = ((astPath.parentFromLevel(2) as unknown) as t.ImportDeclaration).source.value; - const pathPaths = pathName.split('/'); - const maybeAppName = pathPaths.shift(); + const pathParts = pathName.split('/'); + let maybeAppName = pathParts.shift(); - project.roots.forEach((projectRoot) => { - const pkg = getPackageJSON(projectRoot); - let potentialPaths: Location[]; + if (maybeAppName && maybeAppName.startsWith('@')) { + maybeAppName = maybeAppName + path.sep + pathParts.shift(); + } - // If the start of the pathname is same as the project name, then use that as the root. - if (pkg.name === maybeAppName) { - potentialPaths = this.guessPathForImport(projectRoot, uri, pathPaths.join('/')) || []; - } else { - potentialPaths = this.guessPathForImport(projectRoot, uri, pathName) || []; - } + let potentialPaths: Location[]; - definitions = definitions.concat(potentialPaths); - }); + // If the start of the pathname is same as the project name, then use that as the root. + if (project.name === maybeAppName) { + potentialPaths = this.guessPathForImport(project.root, uri, pathParts.join('/')) || []; + } else { + potentialPaths = this.guessPathForImport(project.root, uri, pathName) || []; + } + + definitions = definitions.concat(potentialPaths); } else if (isServiceInjection(astPath)) { let serviceName = ((astPath.node as unknown) as t.Identifier).name; const args = astPath.parent.value.arguments; diff --git a/test/integration-test.ts b/test/integration-test.ts index 27284ada..9ea10a31 100644 --- a/test/integration-test.ts +++ b/test/integration-test.ts @@ -1593,7 +1593,6 @@ describe('integration', function () { }); it('support parent project addon calling child project', async () => { - jest.setTimeout(15000); const result = await getResult( DefinitionRequest.method, connection, From d92f452b043f6601078f6728b839541cdfe2815a Mon Sep 17 00:00:00 2001 From: Suchita Doshi Date: Mon, 12 Apr 2021 12:58:26 -0700 Subject: [PATCH 6/6] address comments --- .../core/script-definition-provider.ts | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/builtin-addons/core/script-definition-provider.ts b/src/builtin-addons/core/script-definition-provider.ts index b438871a..8e2ac0e0 100644 --- a/src/builtin-addons/core/script-definition-provider.ts +++ b/src/builtin-addons/core/script-definition-provider.ts @@ -118,10 +118,6 @@ export default class CoreScriptDefinitionProvider { guessedPaths.push(pathLocation); }); - this.resolvers.resolveTestScopeImport(root, importPath).forEach((pathLocation: string) => { - guessedPaths.push(pathLocation); - }); - return pathsToLocations(...guessedPaths); } guessPathsForType(root: string, fnName: ItemType, typeName: string) { @@ -198,14 +194,21 @@ export default class CoreScriptDefinitionProvider { let maybeAppName = pathParts.shift(); if (maybeAppName && maybeAppName.startsWith('@')) { - maybeAppName = maybeAppName + path.sep + pathParts.shift(); + maybeAppName = maybeAppName + '/' + pathParts.shift(); } let potentialPaths: Location[]; + const addonInfo = project.addonsMeta.find(({ name }) => pathName.startsWith(name + '/tests')); // If the start of the pathname is same as the project name, then use that as the root. - if (project.name === maybeAppName) { - potentialPaths = this.guessPathForImport(project.root, uri, pathParts.join('/')) || []; + if (project.name === maybeAppName && pathName.startsWith(project.name + '/tests')) { + const importPaths = this.resolvers.resolveTestScopeImport(project.root, pathParts.join(path.sep)); + + potentialPaths = pathsToLocations(...importPaths); + } else if (addonInfo) { + const importPaths = this.resolvers.resolveTestScopeImport(addonInfo.root, pathName); + + potentialPaths = pathsToLocations(...importPaths); } else { potentialPaths = this.guessPathForImport(project.root, uri, pathName) || []; }