Fix optional params in bridges function types

This fixes a bug where parameters in Closure functions weren't given the
right combo of non-nullable plus optional tokens.

Fixed: 1126338
Change-Id: I2be2db38bec3dbf278a4bff208dc057447c6ed81
Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/2401016
Commit-Queue: Simon Zünd <szuend@chromium.org>
Reviewed-by: Simon Zünd <szuend@chromium.org>
Auto-Submit: Jack Franklin <jacktfranklin@chromium.org>
This commit is contained in:
Jack Franklin
2020-09-10 06:34:18 +00:00
committed by Commit Bot
parent 91dfe934c7
commit cfd5020c0c
5 changed files with 57 additions and 8 deletions
@@ -17,7 +17,7 @@ import './ComputedStyleProperty.js';
* inherited:boolean,
* traceable:boolean,
* expanded:boolean,
* onNavigateToSource:function(Event):void,
* onNavigateToSource:function(!Event=):void,
* }}
*/
// @ts-ignore we export this for Closure not TS
@@ -14,7 +14,7 @@ import './ComputedStyleTrace.js';
* @typedef {{
* selector:string,
* active:boolean,
* onNavigateToSource:function(Event):void,
* onNavigateToSource:function(!Event=):void,
* }}
*/
// @ts-ignore we export this for Closure not TS
+5 -5
View File
@@ -92,7 +92,7 @@ const createTraceElement = (node, property, isPropertyOverloaded, matchedStyles,
trace.data = {
selector: rule ? rule.selectorText() : 'element.style',
active: !isPropertyOverloaded,
onNavigateToSource: /** @type {function(?Event):void} */ (navigateToSource.bind(null, property)),
onNavigateToSource: /** @type {function(!Event=):void} */ (navigateToSource.bind(null, property)),
};
return trace;
@@ -376,7 +376,7 @@ export class ComputedStyleWidget extends UI.ThrottledWidget.ThrottledWidget {
const propertyElement = createPropertyElement(node, propertyName, propertyValue);
const trace = propertyTraces.get(propertyName);
/** @type {function(?Event):void} */
/** @type {function(!Event=):void} */
let navigate = () => {};
if (trace) {
const traceContainer = document.createElement('div');
@@ -390,7 +390,7 @@ export class ComputedStyleWidget extends UI.ThrottledWidget.ThrottledWidget {
'contextmenu',
this._handleContextMenuEvent.bind(
this, /** @type {!SDK.CSSMatchedStyles.CSSMatchedStyles} */ (matchedStyles), activeProperty));
navigate = /** @type {function(?Event):void} */ (navigateToSource.bind(this, activeProperty));
navigate = /** @type {function(!Event=):void} */ (navigateToSource.bind(this, activeProperty));
propertyElement.appendChild(traceContainer);
propertyElement.addEventListener('traces-toggled', this._onTracesToggled.bind(this));
}
@@ -467,7 +467,7 @@ export class ComputedStyleWidget extends UI.ThrottledWidget.ThrottledWidget {
const propertyElement = createPropertyElement(node, propertyName, propertyValue);
const trace = propertyTraces.get(propertyName);
/** @type {function(?Event):void} */
/** @type {function(!Event=):void} */
let navigate = () => {};
if (trace) {
const traceContainer = document.createElement('div');
@@ -478,7 +478,7 @@ export class ComputedStyleWidget extends UI.ThrottledWidget.ThrottledWidget {
'contextmenu',
this._handleContextMenuEvent.bind(
this, /** @type {!SDK.CSSMatchedStyles.CSSMatchedStyles} */ (matchedStyles), activeProperty));
navigate = /** @type {function(?Event):void} */ (navigateToSource.bind(this, activeProperty));
navigate = /** @type {function(!Event=):void} */ (navigateToSource.bind(this, activeProperty));
propertyElement.appendChild(traceContainer);
propertyElement.addEventListener('traces-toggled', this._onTracesToggled.bind(this));
}
@@ -128,7 +128,22 @@ export const valueForTypeNode = (node: ts.TypeNode, isFunctionParam: boolean = f
if (!param.type) {
return '';
}
return valueForTypeNode(param.type);
const valueForParam = valueForTypeNode(param.type, true);
if (nodeIsPrimitive(param.type)) {
// A primitive never has a ! at the start, but does have a = at the end if it's optional.
return param.questionToken ? `${valueForParam}=` : valueForParam;
}
// If it's not a primitive, it's a type ref and needs a
// non-nullable ! at the start and a = at the end if
// it's optional.
return [
'!',
valueForTypeNode(param.type, true),
param.questionToken ? '=' : '',
].join('');
})
.join(', ');
@@ -237,5 +237,39 @@ describe('valueForTypeNode', () => {
const node = ts.createFunctionTypeNode([], [stringParam], returnUnionNode);
assert.strictEqual(valueForTypeNode(node), 'function(string):(string|undefined)');
});
it('correctly deals with optional type reference parameters', () => {
const stringNode = createNode(ts.SyntaxKind.StringKeyword);
const typeReferenceNode = ts.createTypeReferenceNode(ts.createIdentifier('ExampleInterface'), []);
const functionParam = ts.createParameter(
[], [], undefined, ts.createIdentifier('foo'), ts.createToken(ts.SyntaxKind.QuestionToken),
typeReferenceNode);
// function(foo?: ExampleInterface):string
const node = ts.createFunctionTypeNode([], [functionParam], stringNode);
assert.strictEqual(valueForTypeNode(node), 'function(!ExampleInterface=):string');
});
it('correctly deals with required type reference parameters', () => {
const stringNode = createNode(ts.SyntaxKind.StringKeyword);
const typeReferenceNode = ts.createTypeReferenceNode(ts.createIdentifier('ExampleInterface'), []);
const functionParam =
ts.createParameter([], [], undefined, ts.createIdentifier('foo'), undefined, typeReferenceNode);
// function(foo: ExampleInterface):string
const node = ts.createFunctionTypeNode([], [functionParam], stringNode);
assert.strictEqual(valueForTypeNode(node), 'function(!ExampleInterface):string');
});
it('correctly deals with optional primitive parameters', () => {
const returnTypeNode = createNode(ts.SyntaxKind.StringKeyword);
const stringParam = ts.createParameter(
[], [], undefined, ts.createIdentifier('foo'), ts.createToken(ts.SyntaxKind.QuestionToken),
createNode(ts.SyntaxKind.StringKeyword));
const node = ts.createFunctionTypeNode([], [stringParam], returnTypeNode);
// function(foo?: string):string
assert.strictEqual(valueForTypeNode(node), 'function(string=):string');
});
});
});