chrome-devtools-frontend 1.0.1013298 → 1.0.1014346
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/workflows.md +28 -0
- package/front_end/core/i18n/locales/en-US.json +7 -1
- package/front_end/core/i18n/locales/en-XL.json +7 -1
- package/front_end/models/issues_manager/DeprecationIssue.ts +24 -2
- package/front_end/models/javascript_metadata/DOMPinnedProperties.ts +1754 -0
- package/front_end/models/source_map_scopes/NamesResolver.ts +48 -19
- package/front_end/models/workspace/UISourceCode.ts +1 -1
- package/front_end/panels/lighthouse/LighthouseStartView.ts +1 -0
- package/front_end/panels/sources/TabbedEditorContainer.ts +16 -4
- package/front_end/ui/components/linear_memory_inspector/ValueInterpreterDisplay.ts +6 -6
- package/front_end/ui/components/linear_memory_inspector/valueInterpreterDisplay.css +8 -0
- package/package.json +1 -1
- package/scripts/devtools_paths.js +1 -1
- package/scripts/eslint_rules/lib/check_component_naming.js +14 -6
- package/scripts/eslint_rules/tests/check_component_naming_test.js +23 -0
- package/scripts/webidl-properties/config.js +279 -0
- package/scripts/webidl-properties/get-props.js +139 -0
- package/scripts/webidl-properties/index.js +85 -0
- package/scripts/webidl-properties/package.json +9 -0
- package/scripts/webidl-properties/tests.js +118 -0
- package/scripts/webidl-properties/util.js +81 -0
@@ -0,0 +1,139 @@
|
|
1
|
+
// Copyright 2022 The Chromium Authors. All rights reserved.
|
2
|
+
// Use of this source code is governed by a BSD-style license that can be
|
3
|
+
// found in the LICENSE file.
|
4
|
+
|
5
|
+
import {GLOBAL_ATTRIBUTES, SPECS, VALID_MEMBERS} from './config.js';
|
6
|
+
import {merge} from './util.js';
|
7
|
+
|
8
|
+
/**
|
9
|
+
* All the members relevant for generating the DOM pinned properties dataset
|
10
|
+
* from WebIDL interfaces, mixins and dictionaries.
|
11
|
+
*/
|
12
|
+
const ACCEPTED_MEMBER_TYPES = new Set(['attribute', 'field']);
|
13
|
+
|
14
|
+
/**
|
15
|
+
* Generates the DOM pinned properties dataset.
|
16
|
+
*
|
17
|
+
* @param {array} specs A list of specs. Each spec specifies its name and
|
18
|
+
* all the idl definitions it contains.
|
19
|
+
* @returns {object} output An object with WebIDL type names as keys and their
|
20
|
+
* WebIDL properties and inheritance/include chains as values.
|
21
|
+
*/
|
22
|
+
export function getIDLProps(specs, output = {}) {
|
23
|
+
for (const spec of specs) {
|
24
|
+
transform(spec, output);
|
25
|
+
}
|
26
|
+
return output;
|
27
|
+
}
|
28
|
+
|
29
|
+
function transform({name, idls}, output = {}) {
|
30
|
+
const makeEntry = () => ({
|
31
|
+
inheritance: null,
|
32
|
+
includes: [],
|
33
|
+
props: {},
|
34
|
+
});
|
35
|
+
|
36
|
+
for (const idl of idls) {
|
37
|
+
switch (idl.type) {
|
38
|
+
case 'interface':
|
39
|
+
case 'interface mixin':
|
40
|
+
case 'dictionary': {
|
41
|
+
output[idl.name] = output[idl.name] ?? makeEntry();
|
42
|
+
let props = idl.members?.filter(member => ACCEPTED_MEMBER_TYPES.has(member.type));
|
43
|
+
props = props?.map(member => [member.name, {global: GLOBAL_ATTRIBUTES.has(member.name), specs: [name]}, ]);
|
44
|
+
merge(output[idl.name], {
|
45
|
+
inheritance: idl.inheritance,
|
46
|
+
props: Object.fromEntries(props),
|
47
|
+
});
|
48
|
+
break;
|
49
|
+
}
|
50
|
+
case 'includes': {
|
51
|
+
output[idl.target] = output[idl.target] ?? makeEntry();
|
52
|
+
merge(output[idl.target], {
|
53
|
+
includes: [idl.includes],
|
54
|
+
});
|
55
|
+
break;
|
56
|
+
}
|
57
|
+
case 'callback':
|
58
|
+
case 'callback interface':
|
59
|
+
case 'enum':
|
60
|
+
case 'typedef':
|
61
|
+
case 'namespace': {
|
62
|
+
break;
|
63
|
+
}
|
64
|
+
default: {
|
65
|
+
console.warn('Skipping unknown WebIDL type', idl.type);
|
66
|
+
}
|
67
|
+
}
|
68
|
+
}
|
69
|
+
}
|
70
|
+
|
71
|
+
/**
|
72
|
+
* Adds additional metadata to the DOM pinned properties dataset.
|
73
|
+
*
|
74
|
+
* Currently only adds information about which properties are valid based on
|
75
|
+
* some state, such as for the HTMLInputElement. See `VALID_MEMBERS`.
|
76
|
+
*
|
77
|
+
* @param {*} output
|
78
|
+
*/
|
79
|
+
export function addMetadata(output) {
|
80
|
+
for (const [key, value] of Object.entries(output)) {
|
81
|
+
const rule = VALID_MEMBERS[key];
|
82
|
+
if (!rule) {
|
83
|
+
continue;
|
84
|
+
}
|
85
|
+
const states = Object.entries(rule).map(([selector, allowlist]) => {
|
86
|
+
const valid = Object.entries(value.props).filter(([prop]) => allowlist.has(prop.toLowerCase()));
|
87
|
+
return [selector, Object.fromEntries(valid)];
|
88
|
+
});
|
89
|
+
value.states = Object.fromEntries(states);
|
90
|
+
}
|
91
|
+
return output;
|
92
|
+
}
|
93
|
+
|
94
|
+
/**
|
95
|
+
* Minimizes the DOM pinned properties dataset to remove the bits of data that
|
96
|
+
* don't contain information. For example, empty inheritance/includes chains.
|
97
|
+
*
|
98
|
+
* This should be done right at the end, before writing into the output file, to
|
99
|
+
* allow for certain diagnostics (such as finding "missing types").
|
100
|
+
*
|
101
|
+
* @param {*} output
|
102
|
+
* @returns {object}
|
103
|
+
*/
|
104
|
+
export function minimize(output) {
|
105
|
+
for (const [key, value] of Object.entries(output)) {
|
106
|
+
if (!value.inheritance) {
|
107
|
+
// Remove empty inheritance chains.
|
108
|
+
delete value.inheritance;
|
109
|
+
}
|
110
|
+
if (!value.includes.length) {
|
111
|
+
// Remove empty include chains.
|
112
|
+
delete value.includes;
|
113
|
+
}
|
114
|
+
const props = Object.entries(value.props);
|
115
|
+
if (!props.length) {
|
116
|
+
// Remove empty 'prop' lists.
|
117
|
+
delete value.props;
|
118
|
+
} else {
|
119
|
+
for (const [, value] of props) {
|
120
|
+
if (!value.global) {
|
121
|
+
// Remove the 'global' flag if it's false.
|
122
|
+
delete value.global;
|
123
|
+
}
|
124
|
+
if (value.specs.length === 1 && value.specs[0] === 'html') {
|
125
|
+
// Remove the 'specs' list if it's just "html".
|
126
|
+
delete value.specs;
|
127
|
+
} else {
|
128
|
+
// Combine multiple spec names into a single value.
|
129
|
+
value.specs = value.specs.reduce((acc, name) => acc | SPECS[name], 0);
|
130
|
+
}
|
131
|
+
}
|
132
|
+
}
|
133
|
+
// Remove the entire entry if there's nothing left after the cleanup above.
|
134
|
+
if (!Object.entries(value).length) {
|
135
|
+
delete output[key];
|
136
|
+
}
|
137
|
+
}
|
138
|
+
return output;
|
139
|
+
}
|
@@ -0,0 +1,85 @@
|
|
1
|
+
// Copyright 2020 The Chromium Authors. All rights reserved.
|
2
|
+
// Use of this source code is governed by a BSD-style license that can be
|
3
|
+
// found in the LICENSE file.
|
4
|
+
|
5
|
+
// eslint-disable-next-line rulesdir/es_modules_import
|
6
|
+
import idl from '@webref/idl';
|
7
|
+
import * as fs from 'fs';
|
8
|
+
import * as path from 'path';
|
9
|
+
import * as url from 'url';
|
10
|
+
|
11
|
+
import {SPECS} from './config.js';
|
12
|
+
import {addMetadata, getIDLProps, minimize} from './get-props.js';
|
13
|
+
import {getMissingTypes} from './util.js';
|
14
|
+
|
15
|
+
if (process.argv.length !== 3) {
|
16
|
+
throw new Error('Please provide the path to devtools-frontend');
|
17
|
+
}
|
18
|
+
|
19
|
+
const files = await idl.listAll();
|
20
|
+
const names = Object.keys(SPECS);
|
21
|
+
const specs = await Promise.all(names.map(name => files[name].parse().then(idls => ({name, idls}))));
|
22
|
+
|
23
|
+
const output = addMetadata(getIDLProps(specs));
|
24
|
+
const missing = getMissingTypes(output);
|
25
|
+
|
26
|
+
for (const type of missing) {
|
27
|
+
console.warn('Found missing type:', type);
|
28
|
+
}
|
29
|
+
|
30
|
+
const frontendPath = path.resolve(process.argv[2]);
|
31
|
+
const jsMetadataPath = path.join(frontendPath, 'front_end/models/javascript_metadata/');
|
32
|
+
const outPath = path.join(jsMetadataPath, 'DOMPinnedProperties.ts');
|
33
|
+
const thisPath = path.relative(frontendPath, url.fileURLToPath(import.meta.url));
|
34
|
+
|
35
|
+
fs.writeFileSync(outPath, `
|
36
|
+
// Copyright 2022 The Chromium Authors. All rights reserved.
|
37
|
+
// Use of this source code is governed by a BSD-style license that can be
|
38
|
+
// found in the LICENSE file.
|
39
|
+
// Generated from ${thisPath}
|
40
|
+
|
41
|
+
/**
|
42
|
+
* All the specs used when generating the DOM pinned properties dataset.
|
43
|
+
*/
|
44
|
+
export const SPECS = ${JSON.stringify(SPECS)};
|
45
|
+
|
46
|
+
export interface DOMPinnedWebIDLProp {
|
47
|
+
// A flag specifying whether it's a "global" attribute.
|
48
|
+
global?: boolean;
|
49
|
+
// A bitfield of the specs in which the property is found.
|
50
|
+
// If missing, it implies the default spec: "html".
|
51
|
+
specs?: number;
|
52
|
+
}
|
53
|
+
|
54
|
+
export interface DOMPinnedWebIDLType {
|
55
|
+
// An inherited Type.
|
56
|
+
inheritance?: string;
|
57
|
+
// A set of Types to also include properties from.
|
58
|
+
includes?: Array<string>;
|
59
|
+
// The properties defined on this Type.
|
60
|
+
props?: {
|
61
|
+
// A property name such as "checked".
|
62
|
+
[PropName: string]: DOMPinnedWebIDLProp,
|
63
|
+
};
|
64
|
+
// The "states" in which only certain properties are "applicable".
|
65
|
+
states?: {
|
66
|
+
// A CSS selector such as "[type=checkbox]".
|
67
|
+
[State: string]: {
|
68
|
+
[PropName: string]: DOMPinnedWebIDLProp,
|
69
|
+
},
|
70
|
+
};
|
71
|
+
}
|
72
|
+
|
73
|
+
export interface DOMPinnedPropertiesDataset {
|
74
|
+
[TypeName: string]: DOMPinnedWebIDLType;
|
75
|
+
}
|
76
|
+
|
77
|
+
/**
|
78
|
+
* The DOM pinned properties dataset. Generated from WebIDL data parsed from
|
79
|
+
* the SPECS above.
|
80
|
+
*
|
81
|
+
* This is an object with WebIDL type names as keys and their WebIDL properties
|
82
|
+
* and inheritance/include chains as values.
|
83
|
+
*/
|
84
|
+
export const DOMPinnedProperties: DOMPinnedPropertiesDataset = ${JSON.stringify(minimize(output))};
|
85
|
+
`);
|
@@ -0,0 +1,118 @@
|
|
1
|
+
// Copyright 2022 The Chromium Authors. All rights reserved.
|
2
|
+
// Use of this source code is governed by a BSD-style license that can be
|
3
|
+
// found in the LICENSE file.
|
4
|
+
|
5
|
+
// eslint-disable-next-line rulesdir/es_modules_import
|
6
|
+
import idl from '@webref/idl';
|
7
|
+
import * as assert from 'assert';
|
8
|
+
|
9
|
+
import {SPECS} from './config.js';
|
10
|
+
import {addMetadata, getIDLProps, minimize} from './get-props.js';
|
11
|
+
import {getMissingTypes} from './util.js';
|
12
|
+
|
13
|
+
describe('DOM pinned properties dataset generation', function() {
|
14
|
+
let output;
|
15
|
+
|
16
|
+
this.beforeEach(async () => {
|
17
|
+
const files = await idl.listAll();
|
18
|
+
const names = Object.keys(SPECS);
|
19
|
+
const specs = await Promise.all(names.map(name => files[name].parse().then(idls => ({name, idls}))));
|
20
|
+
output = addMetadata(getIDLProps(specs));
|
21
|
+
});
|
22
|
+
|
23
|
+
it('doesn\'t have missing types', () => {
|
24
|
+
const missing = getMissingTypes(output);
|
25
|
+
assert.strictEqual(missing.length, 0);
|
26
|
+
});
|
27
|
+
|
28
|
+
it('generates valid data for HTMLElement', () => {
|
29
|
+
const type = output.HTMLElement;
|
30
|
+
assert.strictEqual(type.inheritance, 'Element');
|
31
|
+
assert.deepEqual(type.includes, [
|
32
|
+
'GlobalEventHandlers',
|
33
|
+
'DocumentAndElementEventHandlers',
|
34
|
+
'ElementContentEditable',
|
35
|
+
'HTMLOrSVGElement',
|
36
|
+
'ElementCSSInlineStyle',
|
37
|
+
]);
|
38
|
+
assert.deepEqual(type.props.title, {
|
39
|
+
global: true,
|
40
|
+
specs: ['html'],
|
41
|
+
});
|
42
|
+
assert.strictEqual(type.states, undefined);
|
43
|
+
});
|
44
|
+
|
45
|
+
it('generates valid data for HTMLInputElement', () => {
|
46
|
+
const type = output.HTMLInputElement;
|
47
|
+
assert.strictEqual(type.inheritance, 'HTMLElement');
|
48
|
+
assert.deepEqual(type.includes, []);
|
49
|
+
assert.deepEqual(type.props.checked, {
|
50
|
+
global: false,
|
51
|
+
specs: ['html'],
|
52
|
+
});
|
53
|
+
assert.deepEqual(type.states['[type=checkbox]'], {
|
54
|
+
checked: {global: false, specs: ['html']},
|
55
|
+
required: {global: false, specs: ['html']},
|
56
|
+
value: {global: false, specs: ['html']},
|
57
|
+
});
|
58
|
+
});
|
59
|
+
|
60
|
+
it('generates valid data for MouseEvent', () => {
|
61
|
+
const type = output.MouseEvent;
|
62
|
+
assert.strictEqual(type.inheritance, 'UIEvent');
|
63
|
+
assert.deepEqual(type.includes, []);
|
64
|
+
assert.deepEqual(type.props.screenX, {
|
65
|
+
global: false,
|
66
|
+
specs: ['uievents'],
|
67
|
+
});
|
68
|
+
assert.strictEqual(type.states, undefined);
|
69
|
+
});
|
70
|
+
|
71
|
+
it('generates valid data for PointerEvent', () => {
|
72
|
+
const type = output.PointerEvent;
|
73
|
+
assert.strictEqual(type.inheritance, 'MouseEvent');
|
74
|
+
assert.deepEqual(type.includes, []);
|
75
|
+
assert.deepEqual(type.props.pressure, {
|
76
|
+
global: false,
|
77
|
+
specs: ['pointerevents'],
|
78
|
+
});
|
79
|
+
assert.strictEqual(type.states, undefined);
|
80
|
+
});
|
81
|
+
|
82
|
+
it('generates an entry for DOMParser', () => {
|
83
|
+
const type = output.DOMParser;
|
84
|
+
assert.strictEqual(type.inheritance, null);
|
85
|
+
assert.deepEqual(type.includes, []);
|
86
|
+
assert.deepEqual(type.props, {});
|
87
|
+
assert.strictEqual(type.states, undefined);
|
88
|
+
});
|
89
|
+
|
90
|
+
it('minimizes the data for HTMLInputElement', () => {
|
91
|
+
const minimized = minimize(output);
|
92
|
+
const type = minimized.HTMLInputElement;
|
93
|
+
assert.strictEqual(type.inheritance, 'HTMLElement');
|
94
|
+
assert.strictEqual(type.includes, undefined);
|
95
|
+
assert.deepEqual(type.props.checked, {});
|
96
|
+
assert.deepEqual(type.states['[type=checkbox]'], {
|
97
|
+
checked: {},
|
98
|
+
required: {},
|
99
|
+
value: {},
|
100
|
+
});
|
101
|
+
});
|
102
|
+
|
103
|
+
it('minimizes the data for PointerEvent', () => {
|
104
|
+
const minimized = minimize(output);
|
105
|
+
const type = minimized.PointerEvent;
|
106
|
+
assert.strictEqual(type.inheritance, 'MouseEvent');
|
107
|
+
assert.strictEqual(type.includes, undefined);
|
108
|
+
assert.deepEqual(type.props.pressure, {
|
109
|
+
specs: 8,
|
110
|
+
});
|
111
|
+
assert.strictEqual(type.states, undefined);
|
112
|
+
});
|
113
|
+
|
114
|
+
it('removes the entry for DOMParser in the minimized output', () => {
|
115
|
+
const minimized = minimize(output);
|
116
|
+
assert.strictEqual(minimized.DOMParser, undefined);
|
117
|
+
});
|
118
|
+
});
|
@@ -0,0 +1,81 @@
|
|
1
|
+
// Copyright 2022 The Chromium Authors. All rights reserved.
|
2
|
+
// Use of this source code is governed by a BSD-style license that can be
|
3
|
+
// found in the LICENSE file.
|
4
|
+
|
5
|
+
/**
|
6
|
+
* Merges objects or arrays of objects. This is a simplistic merge operation
|
7
|
+
* that is only useful for generating the DOM pinned properties dataset.
|
8
|
+
*
|
9
|
+
* The merge happens in-place: b is merged *into* a.
|
10
|
+
* Both objects must be of the same type.
|
11
|
+
* Arrays are merged as unions with simple same-value-zero equality.
|
12
|
+
* Objects are merged with truthy-property precedence.
|
13
|
+
*
|
14
|
+
* @param {array|object} a
|
15
|
+
* @param {array|object} b
|
16
|
+
*/
|
17
|
+
export function merge(a, b) {
|
18
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
19
|
+
mergeArrays(a, b);
|
20
|
+
} else if (isNonNullObject(a) && isNonNullObject(b)) {
|
21
|
+
mergeObjects(a, b);
|
22
|
+
} else {
|
23
|
+
throw Error;
|
24
|
+
}
|
25
|
+
|
26
|
+
function isNonNullObject(value) {
|
27
|
+
return typeof value === 'object' && value !== null;
|
28
|
+
}
|
29
|
+
|
30
|
+
function mergeArrays(a, b) {
|
31
|
+
const set = new Set(a);
|
32
|
+
for (const value of b) {
|
33
|
+
if (!set.has(value)) {
|
34
|
+
a.push(value);
|
35
|
+
}
|
36
|
+
}
|
37
|
+
}
|
38
|
+
|
39
|
+
function mergeObjects(a, b) {
|
40
|
+
for (const key of Object.keys(b)) {
|
41
|
+
if (isNonNullObject(a[key]) && isNonNullObject(b[key])) {
|
42
|
+
merge(a[key], b[key]);
|
43
|
+
} else {
|
44
|
+
a[key] = a[key] ?? b[key];
|
45
|
+
}
|
46
|
+
}
|
47
|
+
}
|
48
|
+
}
|
49
|
+
|
50
|
+
/**
|
51
|
+
* Finds "missing" types in a DOM pinned properties dataset.
|
52
|
+
* A "missing" type is defined as a type that is inherited or included by/in
|
53
|
+
* another type, but for which a definition wasn't found in the specs.
|
54
|
+
*
|
55
|
+
* This is a helper which helps to ensure that all relevant specs are parsed.
|
56
|
+
* E.g. some specs might reference types defined in other specs.
|
57
|
+
*
|
58
|
+
* @param {object} data
|
59
|
+
* @returns {array}
|
60
|
+
*/
|
61
|
+
export function getMissingTypes(data) {
|
62
|
+
const missing = new Set();
|
63
|
+
const keys = new Set(Object.keys(data));
|
64
|
+
|
65
|
+
for (const value of Object.values(data)) {
|
66
|
+
if (value.inherits) {
|
67
|
+
if (!keys.has(value.inherits)) {
|
68
|
+
missing.add(value.inherits);
|
69
|
+
}
|
70
|
+
}
|
71
|
+
if (value.includes) {
|
72
|
+
for (const include of value.includes) {
|
73
|
+
if (!keys.has(include)) {
|
74
|
+
missing.add(include);
|
75
|
+
}
|
76
|
+
}
|
77
|
+
}
|
78
|
+
}
|
79
|
+
|
80
|
+
return [...missing];
|
81
|
+
}
|