Skip to content

Conversation

@Bashamega
Copy link
Contributor

#2053

Added support for removing items using KDL

@github-actions
Copy link
Contributor

github-actions bot commented Nov 7, 2025

Thanks for the PR!

This section of the codebase is owned by @saschanaz - if they write a comment saying "LGTM" then it will be merged.

@Bashamega
Copy link
Contributor Author

What do you think @saschanaz

@saschanaz
Copy link
Contributor

A bit busy... hopefully this weekend.

@Bashamega
Copy link
Contributor Author

No problem

*/
export default async function readPatches(): Promise<any> {
const patchDirectory = new URL("../../inputfiles/patches/", import.meta.url);
export default async function readPatches(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be sad to put removal files separately. Would be nice if we can:

// ... somenormal patches ...

// and then removals in the same file
removals {
  enum foo { bar }
}

We can extract all removals node from the result of readPatch and then separately return all extracted removals.

Comment on lines 120 to 122
if (node.name === "removals") {
removals = parseKDL(node.children);
continue;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the logic change should rather happen in readPatches.

  1. parse(kdl) can happen in readPatches
  2. readPatches then extracts removals from the resulting Document.
  3. Now readPatches has two Document for each file - the normal and the removals.
  4. Pass that to parseKDL() (which maybe a new name, because it doesn't parse anymore).
  5. Return the results as { patches, removalPatches }. (Then the call can happen once rather than twice.)

*/
function parseKDL(kdlText: string): DeepPartial<WebIdl> {
const { output, errors } = parse(kdlText);
function convertKDLNodes(nodes: Node[] | Document): DeepPartial<WebIdl> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm? Document is equivalent to Node[], this shouldn't be needed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

mixins: { mixin },
interfaces: { interface: interfaces },
dictionaries: { dictionary },
...optionalMember("enums.enum", "object", enums),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this? Why?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still don't understand why this change is needed

const newObj: { [key: string]: unknown } = {};
for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {
if (key !== "name") {
newObj[key] = removeNamesDeep(value);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have a plan how to make nulls work to remove other things than enum values?

@Bashamega
Copy link
Contributor Author

I have fixed it, and added support for dictionaries @saschanaz

mixins: { mixin },
interfaces: { interface: interfaces },
dictionaries: { dictionary },
...optionalMember("enums.enum", "object", enums),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still don't understand why this change is needed

// Accept either Document or array of nodes
const actualNodes: Node[] = Array.isArray(nodes)
? nodes
: nodes;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nodes or nodes is just nodes

return result.length === 0 ? null : result;
}
if (obj && typeof obj === "object") {
const newObj: { [key: string]: unknown } = {};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can use Record here

Bashamega and others added 3 commits December 1, 2025 11:33
Co-authored-by: Kagami Sascha Rosylight <[email protected]>
@Bashamega
Copy link
Contributor Author

Done @saschanaz

dictionaries: {
dictionary,
},
...optionalMember("mixins.mixin", "object", mixin),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same for this and below, and generally the dot accessor thing as a whole.

@Bashamega
Copy link
Contributor Author

Is it better now @saschanaz

interface OverridableMethod extends Omit<Method, "signature"> {
signature: DeepPartial<Signature>[] | Record<number, DeepPartial<Signature>>;
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(this should be restored)

Comment on lines 451 to 453
// Only because we don't use them
removalPatches.mixins = undefined;
removalPatches.interfaces = undefined;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this matter - if we omit this does the test fail?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes without it the tests fail

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes without it the tests fail

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes without it the tests fail

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah because interface: {} becomes interface: null. Hmmmmm I think this may be a footgun later when some patches become redundant and are removed...

* Recursively remove all 'name' fields from the object and its children, and
* replace any empty objects ({} or []) with null.
*/
function sanitizeRemovals(obj: unknown): unknown {
Copy link
Contributor

@saschanaz saschanaz Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

convertForRemovals? It's not really sanitizing - normalizing random user input, but rather converting into a different format.

Co-authored-by: Kagami Sascha Rosylight <[email protected]>
Bashamega and others added 4 commits December 2, 2025 07:58
@Bashamega
Copy link
Contributor Author

Thanks @saschanaz
Is there anything else left?

@saschanaz
Copy link
Contributor

LGTM, thanks!

@github-actions github-actions bot merged commit 9969062 into microsoft:main Dec 2, 2025
5 checks passed
@github-actions
Copy link
Contributor

github-actions bot commented Dec 2, 2025

Merging because @saschanaz is a code-owner of all the changes - thanks!

@saschanaz saschanaz deleted the removals branch December 2, 2025 09:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants