-
-
Notifications
You must be signed in to change notification settings - Fork 63
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: allow adding additional members to production parse methods (#745
) * feat: allow adding additional members to production parse methods * feat: add 'extensions' option for extending existing productions * fix: remove unnecessary spread operator Co-authored-by: Kagami Sascha Rosylight <[email protected]> * refactor: rename extension 'callback-interface' to callbackInterface * test: improve extension parsing tests * docs: fix up jsdoc definition for ParserOptions * test: remove use strict * test: merge extension test into custom-production * test: replace customProduction with top-level CustomAttribute * test: remove extension argument from collection utility * docs: normalize use of Token import * test: fix import of expect function * docs: mark args as any This is also due to microsoft/TypeScript#4628 which prevents changing the signature of static methods on inherited classes. * docs: fix path to container.js * refactor: remove unnecessary spread operator * docs: fix jsdoc types Co-authored-by: Kagami Sascha Rosylight <[email protected]> * docs: fix jsdoc types Co-authored-by: Kagami Sascha Rosylight <[email protected]> * fix: remove iheritance attribute from CallbackInterface --------- Co-authored-by: Kagami Sascha Rosylight <[email protected]>
- Loading branch information
Showing
9 changed files
with
155 additions
and
75 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,51 +1,87 @@ | ||
"use strict"; | ||
|
||
import { expect } from "expect"; | ||
import { parse, write } from "webidl2"; | ||
|
||
describe("Writer template functions", () => { | ||
const customIdl = ` | ||
interface X {}; | ||
custom Y; | ||
`; | ||
import { parse, write } from "webidl2"; | ||
import { Base } from "../lib/productions/base.js"; | ||
import { | ||
autoParenter, | ||
type_with_extended_attributes, | ||
} from "../lib/productions/helpers.js"; | ||
|
||
/** | ||
* @param {import("../lib/tokeniser").Tokeniser} tokeniser | ||
*/ | ||
const customProduction = (tokeniser) => { | ||
const { position } = tokeniser; | ||
const base = tokeniser.consumeIdentifier("custom"); | ||
if (!base) { | ||
return; | ||
} | ||
const tokens = { base }; | ||
tokens.name = tokeniser.consumeKind("identifier"); | ||
tokens.termination = tokeniser.consume(";"); | ||
if (!tokens.name || !tokens.termination) { | ||
tokeniser.unconsume(position); | ||
class CustomAttribute extends Base { | ||
static parse(tokeniser) { | ||
const start_position = tokeniser.position; | ||
const tokens = {}; | ||
const ret = autoParenter( | ||
new CustomAttribute({ source: tokeniser.source, tokens }) | ||
); | ||
tokens.base = tokeniser.consumeIdentifier("custom"); | ||
if (!tokens.base) { | ||
tokeniser.unconsume(start_position); | ||
return; | ||
} | ||
return { | ||
type: "custom", | ||
tokens, | ||
/** @param {import("../lib/writer.js").Writer} w */ | ||
write(w) { | ||
return w.ts.wrap([ | ||
w.token(this.tokens.base), | ||
w.token(this.tokens.name), | ||
w.token(this.tokens.termination), | ||
]); | ||
}, | ||
}; | ||
}; | ||
ret.idlType = | ||
type_with_extended_attributes(tokeniser, "attribute-type") || | ||
tokeniser.error("Attribute lacks a type"); | ||
tokens.name = | ||
tokeniser.consumeKind("identifier") || | ||
tokeniser.error("Attribute lacks a name"); | ||
tokens.termination = | ||
tokeniser.consume(";") || | ||
tokeniser.error("Unterminated attribute, expected `;`"); | ||
return ret.this; | ||
} | ||
|
||
const result = parse(customIdl, { | ||
productions: [customProduction], | ||
concrete: true, | ||
get type() { | ||
return "custom attribute"; | ||
} | ||
|
||
write(w) { | ||
const { parent } = this; | ||
return w.ts.definition( | ||
w.ts.wrap([ | ||
this.extAttrs.write(w), | ||
w.token(this.tokens.base), | ||
w.ts.type(this.idlType.write(w)), | ||
w.name_token(this.tokens.name, { data: this, parent }), | ||
w.token(this.tokens.termination), | ||
]), | ||
{ data: this, parent } | ||
); | ||
} | ||
} | ||
|
||
describe("Parse IDLs using custom productions", () => { | ||
it("Parse and rewrite top-level custom attribute", () => { | ||
const customIdl = "custom long bar;"; | ||
const result = parse(customIdl, { | ||
productions: [CustomAttribute.parse], | ||
concrete: true, | ||
}); | ||
expect(result[0].type).toBe("custom attribute"); | ||
|
||
const rewritten = write(result); | ||
expect(rewritten).toBe(customIdl); | ||
}); | ||
expect(result[0].type).toBe("interface"); | ||
expect(result[1].type).toBe("custom"); | ||
}); | ||
|
||
const rewritten = write(result); | ||
expect(rewritten).toBe(customIdl); | ||
describe("Parse IDLs using custom extensions", () => { | ||
[ | ||
["callback interface", "callbackInterface"], | ||
["dictionary", "dictionary"], | ||
["interface", "interface"], | ||
["interface mixin", "mixin"], | ||
["namespace", "namespace"], | ||
].forEach(([type, key]) => { | ||
it(`Attribute on ${type}`, () => { | ||
const customIdl = `${type} Foo { | ||
custom long bar; | ||
};`; | ||
const result = parse(customIdl, { | ||
concrete: true, | ||
extensions: { [key]: { extMembers: [[CustomAttribute.parse]] } }, | ||
}); | ||
expect(result[0].type).toBe(type); | ||
expect(result[0].members[0].type).toBe("custom attribute"); | ||
}); | ||
}); | ||
}); |