-
Notifications
You must be signed in to change notification settings - Fork 1.7k
[DebuggerV2] Add shim for loadMonaco() method and supporting external libraries #3374
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
85a2058
4635de9
206bc5b
4effe98
7d6bcc9
48276ca
db4c5ac
5c2d9ca
dcae661
f9da801
77b5d5d
5e85212
f89ed47
97c38a0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| package(default_visibility = ["//tensorboard:internal"]) | ||
|
|
||
| load("//tensorboard/defs:defs.bzl", "tf_ts_library") | ||
|
|
||
| licenses(["notice"]) # Apache 2.0 | ||
|
|
||
| tf_ts_library( | ||
| name = "load_monaco", | ||
| srcs = [ | ||
| "load_monaco_shim.ts", | ||
| ], | ||
| deps = [ | ||
| "@npm//@types/requirejs", | ||
| ], | ||
| ) | ||
|
|
||
| tf_ts_library( | ||
| name = "source_code_test_lib", | ||
| testonly = True, | ||
| srcs = [ | ||
| "load_monaco_shim_test.ts", | ||
| ], | ||
| tsconfig = "//:tsconfig-test", | ||
| deps = [ | ||
| ":load_monaco", | ||
| "@npm//@types/jasmine", | ||
| "@npm//@types/requirejs", | ||
| ], | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| /* Copyright 2020 The TensorFlow Authors. All Rights Reserved. | ||
|
|
||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||
| you may not use this file except in compliance with the License. | ||
| You may obtain a copy of the License at | ||
|
|
||
| http://www.apache.org/licenses/LICENSE-2.0 | ||
|
|
||
| Unless required by applicable law or agreed to in writing, software | ||
| distributed under the License is distributed on an "AS IS" BASIS, | ||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| See the License for the specific language governing permissions and | ||
| limitations under the License. | ||
| ==============================================================================*/ | ||
| /** | ||
| * Shim for the `loadMonaco()` function in different build environments. | ||
| * | ||
| * This file exports the version of `loadMonaco()` appropriate for the | ||
| * open-source environment. | ||
| */ | ||
|
|
||
| // TODO(cais): Explore better typing by depending on external libraries. | ||
| export interface WindowWithRequireAndMonaco extends Window { | ||
| require?: Require; | ||
| monaco?: any; | ||
| } | ||
| export const windowWithRequireAndMonaco: WindowWithRequireAndMonaco = window; | ||
|
|
||
| const MONACO_PATH_PREFIX = 'vs'; | ||
| const MONACO_IMPORT_PATH = '/tf-imports/vs'; | ||
|
|
||
| /** | ||
| * require.js's require() wrapped as an async function that returns a Promise. | ||
| * | ||
| * This wrapped version does not support callback-function arguments. | ||
| * | ||
| * @param paths | ||
| */ | ||
| function requireAsPromise(paths: string[]): Promise<void> { | ||
| const require = windowWithRequireAndMonaco.require!; | ||
| return new Promise((resolve) => { | ||
| require(paths, resolve); | ||
| }); | ||
| } | ||
|
|
||
| /** | ||
| * If `window.monaco` is undefined, load the monaco-editor API object onto that | ||
| * global path dynamically using require.js. If `window.monaco` is already | ||
| * defined, this function is a no-op. | ||
| */ | ||
| export async function loadMonaco(): Promise<void> { | ||
| if (windowWithRequireAndMonaco.monaco !== undefined) { | ||
| return; | ||
| } | ||
|
|
||
| if (windowWithRequireAndMonaco.require) { | ||
| const require = windowWithRequireAndMonaco.require; | ||
| require.config({ | ||
| paths: { | ||
| [MONACO_PATH_PREFIX]: MONACO_IMPORT_PATH, | ||
| }, | ||
| }); | ||
| await requireAsPromise([`${MONACO_PATH_PREFIX}/editor/editor.main`]); | ||
| await requireAsPromise([ | ||
| `${MONACO_PATH_PREFIX}/python/python.contribution`, | ||
| ]); | ||
| } else { | ||
| throw new Error( | ||
| 'loadMonaco() failed because function require() is unavailable' | ||
| ); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| /* Copyright 2020 The TensorFlow Authors. All Rights Reserved. | ||
|
|
||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||
| you may not use this file except in compliance with the License. | ||
| You may obtain a copy of the License at | ||
|
|
||
| http://www.apache.org/licenses/LICENSE-2.0 | ||
|
|
||
| Unless required by applicable law or agreed to in writing, software | ||
| distributed under the License is distributed on an "AS IS" BASIS, | ||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| See the License for the specific language governing permissions and | ||
| limitations under the License. | ||
| ==============================================================================*/ | ||
|
|
||
| import {loadMonaco, windowWithRequireAndMonaco} from './load_monaco_shim'; | ||
|
|
||
| describe('loadMonaco shim', () => { | ||
| function createFakeRequire(): Require { | ||
| let require = ((modules: string[], callback: Function) => { | ||
| callback(); | ||
| }) as any; | ||
| return Object.assign(require, { | ||
| config: () => {}, | ||
| toUrl: () => {}, | ||
| defined: () => {}, | ||
| specified: () => {}, | ||
| onError: () => {}, | ||
| undef: () => {}, | ||
| onResourceLoad: () => {}, | ||
| }); | ||
| } | ||
|
|
||
| // TODO(cais): Explore better typing by depending on external libraries. | ||
| function createFakeMonaco() { | ||
| return {}; | ||
| } | ||
|
|
||
| let requireSpy: jasmine.Spy; | ||
| beforeEach(() => { | ||
| windowWithRequireAndMonaco.require = createFakeRequire(); | ||
| requireSpy = spyOn(windowWithRequireAndMonaco, 'require').and.callThrough(); | ||
| }); | ||
|
|
||
| afterEach(() => { | ||
| delete windowWithRequireAndMonaco.require; | ||
| delete windowWithRequireAndMonaco.monaco; | ||
| }); | ||
|
|
||
| it('async function returns without error', async () => { | ||
| await loadMonaco(); | ||
| expect(requireSpy).toHaveBeenCalled(); | ||
| }); | ||
|
|
||
| it('does not reload monaco module if already loaded', async () => { | ||
| windowWithRequireAndMonaco.monaco = createFakeMonaco(); | ||
| await loadMonaco(); | ||
| expect(requireSpy).not.toHaveBeenCalled(); | ||
| }); | ||
|
|
||
| it('rejects if require.js is unavailable', async (done) => { | ||
| delete windowWithRequireAndMonaco.require; | ||
| // TODO(cais): Use async matchers such as toBeRejectedWithError once they | ||
| // are available. | ||
| try { | ||
| await loadMonaco(); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I forget which version of jasmine we are using but you should be able to use:
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was looking to use the same thing, but it turns out that the version of jasmine we're using (@bazel/jasmine, 0.32.2) doesn't have async matchers such as |
||
| done.fail(); | ||
| } catch (e) { | ||
| done(); | ||
| } | ||
| }); | ||
| }); | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use proper jasmine API?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried that and it didn't work, because
window.requiredoesn't exist or have an accessor type.