-
-
Notifications
You must be signed in to change notification settings - Fork 393
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
fix(core/dfn): treat internal slots as IDL attributes #3646
Changes from 19 commits
a836e8a
700a8e1
0d5c2d8
204af22
fb81bb0
04ee056
aeeea2d
500895f
45cbbaa
074d0d9
a665899
c5d8632
a12748f
bf914ed
9e0cf9d
6b235d0
cd0468a
061a6df
e57dbeb
f029503
567761c
c8c99c4
2e7e714
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 |
---|---|---|
|
@@ -7,16 +7,18 @@ import { html } from "./import-maps.js"; | |
const idlPrimitiveRegex = /^[a-z]+(\s+[a-z]+)+\??$/; // {{unrestricted double?}} {{ double }} | ||
const exceptionRegex = /\B"([^"]*)"\B/; // {{ "SomeException" }} | ||
const methodRegex = /(\w+)\((.*)\)$/; | ||
const slotRegex = /^\[\[(\w+)\]\]$/; | ||
|
||
export const slotRegex = /^\[\[(\w+(?: +\w+)*)\]\](\([^)]*\))?$/; | ||
// matches: `value` or `[[value]]` | ||
// NOTE: [[value]] is actually a slot, but database has this as type="attribute" | ||
const attributeRegex = /^((?:\[\[)?(?:\w+)(?:\]\])?)$/; | ||
const attributeRegex = /^((?:\[\[)?(?:\w+(?: +\w+)*)(?:\]\])?)$/; | ||
const baseRegex = /^(?:\w+)\??$/; | ||
const enumRegex = /^(\w+)\["([\w- ]*)"\]$/; | ||
// TODO: const splitRegex = /(?<=\]\]|\b)\./ | ||
// https://github.com/w3c/respec/pull/1848/files#r225087385 | ||
const methodSplitRegex = /\.?(\w+\(.*\)$)/; | ||
|
||
const slotSplitRegex = /\.?\/(.+)/; | ||
marcoscaceres marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const isProbablySlotRegex = /^\[\[.+\]\]/; | ||
/** | ||
* @typedef {object} IdlBase | ||
* @property {"base"} type | ||
|
@@ -34,8 +36,10 @@ const methodSplitRegex = /\.?(\w+\(.*\)$)/; | |
* @typedef {object} IdlInternalSlot | ||
* @property {"internal-slot"} type | ||
* @property {string} identifier | ||
* @property {string[]} [args] | ||
* @property {boolean} renderParent | ||
* @property {InlineIdl | null} [parent] | ||
* @property {"attribute"|"method"} slotType | ||
* | ||
* @typedef {object} IdlMethod | ||
* @property {"method"} type | ||
|
@@ -71,7 +75,11 @@ const methodSplitRegex = /\.?(\w+\(.*\)$)/; | |
* @returns {InlineIdl[]} | ||
*/ | ||
function parseInlineIDL(str) { | ||
const [nonMethodPart, methodPart] = str.split(methodSplitRegex); | ||
// If it's got [[ string ]], then split as an internal slot | ||
const splitter = isProbablySlotRegex.test(str) | ||
? slotSplitRegex | ||
: methodSplitRegex; | ||
const [nonMethodPart, methodPart] = str.split(splitter); | ||
const tokens = nonMethodPart | ||
.split(/[./]/) | ||
.concat(methodPart) | ||
|
@@ -108,8 +116,19 @@ function parseInlineIDL(str) { | |
} | ||
// internal slot | ||
if (slotRegex.test(value)) { | ||
const [, identifier] = value.match(slotRegex); | ||
results.push({ type: "internal-slot", identifier, renderParent }); | ||
const [, identifier, allArgs] = value.match(slotRegex); | ||
const slotType = allArgs ? "method" : "attribute"; | ||
const args = allArgs | ||
?.slice(1, -1) | ||
.split(/,\s*/) | ||
.filter(arg => arg); | ||
results.push({ | ||
type: "internal-slot", | ||
slotType, | ||
identifier, | ||
args, | ||
renderParent, | ||
}); | ||
continue; | ||
} | ||
// attribute | ||
|
@@ -167,15 +186,20 @@ function renderBase(details) { | |
* @param {IdlInternalSlot} details | ||
*/ | ||
function renderInternalSlot(details) { | ||
const { identifier, parent, renderParent } = details; | ||
const { identifier, parent, slotType, renderParent, args } = details; | ||
const { identifier: linkFor } = parent || {}; | ||
const lt = `[[${identifier}]]`; | ||
const isMethod = slotType === "method"; | ||
const argsHtml = isMethod | ||
? htmlJoinComma(args, arg => html`<var>${arg}</var>`) | ||
: null; | ||
const textArgs = isMethod ? `(${args.join(", ")})` : ""; | ||
const lt = `[[${identifier}]]${textArgs}`; | ||
const element = html`${parent && renderParent ? "." : ""}<a | ||
data-xref-type="attribute" | ||
data-link-for=${linkFor} | ||
data-xref-for=${linkFor} | ||
data-xref-type="${slotType}" | ||
data-link-for="${linkFor}" | ||
data-xref-for="${linkFor}" | ||
data-lt="${lt}" | ||
><code>[[${identifier}]]</code></a | ||
><code>[[${identifier}]]${isMethod ? html`(${argsHtml})` : null}</code></a | ||
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. Can probably merge this into |
||
>`; | ||
return element; | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -153,4 +153,75 @@ describe("Core — Definitions", () => { | |
expect(el.hash).toBe("#dfn-first"); | ||
} | ||
}); | ||
|
||
describe("internal slot definitions", () => { | ||
const body = ` | ||
<section data-dfn-for="Test" data-cite="HTML"> | ||
<h2>Internal slots</h2> | ||
<pre class="idl"> | ||
[Exposed=Window] | ||
interface Foo{}; | ||
</pre> | ||
<p> | ||
<dfn id="attribute"> | ||
[[\\internal slot]] | ||
</dfn> | ||
<dfn id="method"> | ||
[[\\I am_a method]](I, really, ...am) | ||
</dfn> | ||
<dfn id="parent" data-dfn-for="Window">[[\\internal slot]]</dfn> | ||
<dfn id="broken" data-dfn-for="">[[\\broken]]</dfn> | ||
</p> | ||
<section data-dfn-for=""> | ||
<h2>.</h2> | ||
<p> | ||
<dfn id="broken-parent">[[\\broken]]</dfn> | ||
</p> | ||
</section> | ||
<p> | ||
{{Test/[[internal slot]]}} | ||
{{Test/[[I am_a method]](I, really, ...am)}} | ||
{{Window/[[internal slot]]}} | ||
</p> | ||
</section> | ||
`; | ||
|
||
it("sets the data-dfn-type as an attribute", async () => { | ||
const ops = makeStandardOps(null, body); | ||
const doc = await makeRSDoc(ops); | ||
Comment on lines
+190
to
+191
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. This is repeated (with same args) in each test here. Can probably move it into a 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. It's specific to this particular 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 think 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. Ok, will try. The docs said they beforeAll was global. |
||
const dfn = doc.getElementById("attribute"); | ||
expect(dfn.textContent.trim()).toBe("[[internal slot]]"); | ||
expect(dfn.dataset.dfnType).toBe("attribute"); | ||
expect(dfn.dataset.idl).toBe(""); | ||
}); | ||
|
||
it("sets the data-dfn-type as a method, when it's a method", async () => { | ||
const ops = makeStandardOps(null, body); | ||
const doc = await makeRSDoc(ops); | ||
const dfn = doc.getElementById("method"); | ||
expect(dfn.textContent.trim()).toBe( | ||
"[[I am_a method]](I, really, ...am)" | ||
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. Are spaces acceptable in internal slot names? Any real world examples? 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. there are no rules, which is another reason why I'm not very comfortable with labeling them as attributes; there are real-world examples of spaces in internal slots, like 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 should've checked given I wrote the filter tool 😆) 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. Though, at least no internalSlot-method with spaces. |
||
); | ||
expect(dfn.dataset.dfnType).toBe("method"); | ||
expect(dfn.dataset.idl).toBe(""); | ||
}); | ||
|
||
it("when data-dfn-for is missing, it use the closes data-dfn-for as parent", async () => { | ||
const ops = makeStandardOps(null, body); | ||
const doc = await makeRSDoc(ops); | ||
const dfn = doc.getElementById("attribute"); | ||
expect(dfn.dataset.dfnFor).toBe("Test"); | ||
const dfnWithParent = doc.getElementById("parent"); | ||
expect(dfnWithParent.dataset.dfnFor).toBe("Window"); | ||
}); | ||
|
||
it("errors if the internal slot is not for something", async () => { | ||
const ops = makeStandardOps(null, body); | ||
const doc = await makeRSDoc(ops); | ||
const dfnErrors = doc.respec.errors.filter( | ||
({ plugin }) => plugin === "core/dfn" | ||
); | ||
expect(dfnErrors).toHaveSize(2); | ||
}); | ||
}); | ||
}); |
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.
Wow, interesting!
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.
We will eventually need a way to actually verify this... but pretty cool if we can do that!