Skip to content
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

chore(api): Make macros with line breaks span a single line only #32510

Closed
wants to merge 5 commits into from

Conversation

bsmth
Copy link
Member

@bsmth bsmth commented Mar 1, 2024

Description

This PR replaces macros that break across multiple lines with single-line invocations.

Motivation

It's impossible to search through the source for a specific pattern without missing edge cases where macros break across multiple lines. The lack of uniformity of this particular case has resulted in missing certain usages very often, such as (EmbedLiveSample calls that contain .pngs), i.e.:

{{ EmbedLiveSample('Different_shapes_demonstrated', 160, 210,
  "canvas_arc.png") }}

It appears that in a lot of cases, this pattern was created through search/replace, and hints at related errors introduced from trying to handle these cases

{{macro("thing",
"title")}}`

See stencil`")}} and premultipliedAlpha`")}}

@bsmth bsmth requested review from a team as code owners March 1, 2024 13:55
@bsmth bsmth requested review from wbamberg and teoli2003 and removed request for a team March 1, 2024 13:55
@github-actions github-actions bot added Content:WebAPI Web API docs Content:JS JavaScript docs Content:HTTP HTTP docs size/m [PR only] 51-500 LoC changed labels Mar 1, 2024
Copy link
Contributor

github-actions bot commented Mar 1, 2024

Preview URLs (220 pages)
Flaws (15)

Note! 207 documents with no flaws that don't need to be listed. 🎉

URL: /en-US/docs/Web/API/RTCInboundRtpStreamStats/sliCount
Title: RTCInboundRtpStreamStats: sliCount property
Flaw count: 1

  • bad_bcd_queries:
    • No BCD data for query: api.RTCInboundRtpStreamStats.sliCount

URL: /en-US/docs/Web/API/RTCError
Title: RTCError
Flaw count: 1

  • macros:
    • /en-US/docs/Web/API/RTCError/RTCError does not exist

URL: /en-US/docs/Web/API/RTCIceCandidatePairStats/availableIncomingBitrate
Title: RTCIceCandidatePairStats: availableIncomingBitrate property
Flaw count: 1

  • bad_bcd_queries:
    • No BCD data for query: api.RTCIceCandidatePairStats.availableIncomingBitrate

URL: /en-US/docs/Web/API/XRReferenceSpace/getOffsetReferenceSpace
Title: XRReferenceSpace: getOffsetReferenceSpace() method
Flaw count: 1

  • macros:
    • /en-US/docs/Web/API/Element/oncontextmenu does not exist

URL: /en-US/docs/Web/API/KeyboardEvent/charCode
Title: KeyboardEvent: charCode property
Flaw count: 2

  • macros:
    • /en-US/docs/Glossary/IME does not exist
  • broken_links:
    • Can't resolve /en-US/docs/Gecko_Keypress_Event

URL: /en-US/docs/Web/API/HTMLImageElement/x
Title: HTMLImageElement: x property
Flaw count: 1

  • macros:
    • /en-US/docs/Web/API/HTMLTableRowElement/cells does not exist

URL: /en-US/docs/Web/API/HTMLAudioElement/Audio
Title: HTMLAudioElement: Audio() constructor
Flaw count: 1

  • macros:
    • /en-US/docs/Web/API/HTMLMediaElement/preload does not exist

URL: /en-US/docs/Web/API/RTCOutboundRtpStreamStats/sliCount
Title: RTCOutboundRtpStreamStats: sliCount property
Flaw count: 1

  • bad_bcd_queries:
    • No BCD data for query: api.RTCOutboundRtpStreamStats.sliCount

URL: /en-US/docs/Web/API/RTCOutboundRtpStreamStats/qualityLimitationReason
Title: RTCOutboundRtpStreamStats: qualityLimitationReason property
Flaw count: 2

  • macros:
    • /en-US/docs/Web/API/RTCOutboundRtpStreamStats/qualityLimitationDurations does not exist
  • bad_bcd_queries:
    • No BCD data for query: api.RTCOutboundRtpStreamStats.qualityLimitationReason

URL: /en-US/docs/Web/API/RTCPeerConnection/setRemoteDescription
Title: RTCPeerConnection: setRemoteDescription() method
Flaw count: 1

  • macros:
    • /en-US/docs/Web/API/RTCSessionDescriptionInit does not exist

URL: /en-US/docs/Web/API/RTCPeerConnection/createAnswer
Title: RTCPeerConnection: createAnswer() method
Flaw count: 1

  • macros:
    • /en-US/docs/Web/API/RTCSessionDescriptionInit does not exist

URL: /en-US/docs/Web/API/RTCPeerConnection/setLocalDescription
Title: RTCPeerConnection: setLocalDescription() method
Flaw count: 1

  • macros:
    • /en-US/docs/Web/API/RTCSessionDescriptionInit does not exist

URL: /en-US/docs/Web/API/RTCIceParameters/password
Title: RTCIceParameters: password property
Flaw count: 1

  • bad_bcd_queries:
    • No BCD data for query: api.RTCIceParameters.password
External URLs (3)

URL: /en-US/docs/Web/API/OscillatorNode/type
Title: OscillatorNode: type property


URL: /en-US/docs/Web/API/Event/cancelable
Title: Event: cancelable property


URL: /en-US/docs/Web/API/Response/json
Title: Response: json() method

(comment last updated: 2024-03-05 12:10:18)

@bsmth bsmth added the macros Work relating to macro refactoring or removal label Mar 1, 2024
@bsmth bsmth requested a review from Josh-Cena March 1, 2024 17:47
Copy link
Contributor

@OnkarRuikar OnkarRuikar left a comment

Choose a reason for hiding this comment

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

There are more cases of {{ domxref("abc")}} or {{domxref("abc") }} than I've reportd.

Which one do we prefer?

  • {{ domxref("abc") }} or
  • {{domxref("abc")}}

The **`duration`** property of the {{ domxref("AudioBuffer")
}} interface returns a double representing the duration, in seconds, of the PCM data
stored in the buffer.
The **`duration`** property of the {{ domxref("AudioBuffer")}}
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
The **`duration`** property of the {{ domxref("AudioBuffer")}}
The **`duration`** property of the {{domxref("AudioBuffer")}}

pass {{ domxref("BiquadFilterNode") }} (which effectively serves as a bass booster),
In this example, we grab a media (audio + video) stream from {{domxref("navigator.getUserMedia")}}, feed the media into a {{htmlelement("video")}}
element to play then mute the audio, but then also feed the audio into a {{domxref("MediaStreamAudioSourceNode")}}.
Next, we feed this source audio into a low pass {{ domxref("BiquadFilterNode") }} (which effectively serves as a bass booster),
then a {{domxref("AudioDestinationNode") }}.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
then a {{domxref("AudioDestinationNode") }}.
then a {{domxref("AudioDestinationNode")}}.

@@ -10,8 +10,7 @@ browser-compat: api.BaseAudioContext.createBuffer

The `createBuffer()` method of the {{ domxref("BaseAudioContext") }}
Interface is used to create a new, empty {{ domxref("AudioBuffer") }} object, which
can then be populated by data, and played via an {{ domxref("AudioBufferSourceNode")
}}
can then be populated by data, and played via an {{ domxref("AudioBufferSourceNode")}}.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
can then be populated by data, and played via an {{ domxref("AudioBufferSourceNode")}}.
can then be populated by data, and played via an {{domxref("AudioBufferSourceNode")}}.

Comment on lines +13 to +14
used to play audio data contained within an {{ domxref("AudioBuffer") }} object.
{{domxref("AudioBuffer") }}s are created using
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
used to play audio data contained within an {{ domxref("AudioBuffer") }} object.
{{domxref("AudioBuffer") }}s are created using
used to play audio data contained within an {{ domxref("AudioBuffer") }} object.
{{domxref("AudioBuffer")}}s are created using

@@ -8,8 +8,7 @@ browser-compat: api.BiquadFilterNode.getFrequencyResponse

{{ APIRef("Web Audio API") }}

The `getFrequencyResponse()` method of the {{ domxref("BiquadFilterNode")
}} interface takes the current filtering algorithm's settings and calculates the
The `getFrequencyResponse()` method of the {{ domxref("BiquadFilterNode")}} interface takes the current filtering algorithm's settings and calculates the
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
The `getFrequencyResponse()` method of the {{ domxref("BiquadFilterNode")}} interface takes the current filtering algorithm's settings and calculates the
The `getFrequencyResponse()` method of the {{domxref("BiquadFilterNode")}} interface takes the current filtering algorithm's settings and calculates the

@hamishwillee
Copy link
Collaborator

There are more cases of {{ domxref("abc")}} or {{domxref("abc") }} than I've reportd.

Which one do we prefer?

  • {{ domxref("abc") }} or
  • {{domxref("abc")}}

I much prefer the second. It is more compact and the whitespace isn't helpful.

@OnkarRuikar
Copy link
Contributor

  • {{ domxref("abc") }} or
  • {{domxref("abc")}}

I much prefer the second. It is more compact and the whitespace isn't helpful.

We can have this consistent repo wide by adding a custom rule to our linter:

content/.markdownlint.jsonc

Lines 175 to 179 in 17db3c0

"name": "double-spaces",
"message": "Avoid double spaces",
"searchPattern": "/([^\\s>]) ([^\\s|])/g",
"replace": "$1 $2",
"searchScope": "text",

@bsmth
Copy link
Member Author

bsmth commented Mar 4, 2024

Thank you for the comments @OnkarRuikar - I agree with all of these suggestions. Shall I handle these in a separate PR? I wanted to keep this one about \n newlines only (for reviewers, mainly).

There are more cases of {{ domxref("abc")}} or {{domxref("abc") }} than I've reportd.

Which one do we prefer?

* `{{ domxref("abc") }}` or

* `{{domxref("abc")}}`

Agree with Hamish on this, +1 to the second format.

@OnkarRuikar
Copy link
Contributor

Shall I handle these in a separate PR?

👍 Yes, that will be easy to fix and review.

@wbamberg
Copy link
Collaborator

wbamberg commented Mar 4, 2024

I'm not exactly against this change, but:

  • it's a big PR that's quite hard for humans to review reliably (i.e. without introducing new errors). Do we have any confirmation that this PR doesn't add any macro errors? (and produces the exact same output as before?)
  • it's not exactly true that "It's impossible to search through the source for a specific pattern without missing edge cases where macros break across multiple lines". It's impossible to use grep to look for macro invocations, but that's always going to be unreliable.
  • if we are going to rely on macros not containing linebreaks, how do we stop them reappearing?

It appears that in a lot of cases, this pattern was created through search/replace, and hints at related errors introduced from trying to handle these cases

At least in the two cases you listed, this isn't the case: the linebreak didn't exist before the error was introduced.

Personally I think that rather than using grep it would be better to use tools that are less prone to breaking. For example, I just published https://www.npmjs.com/package/query-kumascript, which uses the KS parser to find macro invocations. It seems like this would be more reliable.

@OnkarRuikar
Copy link
Contributor

OnkarRuikar commented Mar 5, 2024

it's a big PR that's quite hard for humans to review reliably (i.e. without introducing new errors). Do we have any confirmation that this PR doesn't add any macro errors? (and produces the exact same output as before?)

In a similar case for formal syntax changes I did complete yari builds of before and after changes. And compared the build directories using a visual diff tool Meld. Or we could reduce the batch size to 30 and do 7 PRs.

if we are going to rely on macros not containing linebreaks, how do we stop them reappearing?

We already have a mechanism in place to lint such custom cases. Following rule in .markdownlint.jsonc should work:

{
"name": "linebreaks-in-macros", 
 "message": "Avoid linebreaks in macro calls", 
 "searchPattern": "/\\{\\{[^{}]*?\n[^{|]*?\\}\\}/g", 
 "searchScope": "text", 
}

The regex may need some tuning.

I just published npmjs.com/package/query-kumascript, which uses the KS parser to find macro invocations. It seems like this would be more reliable.

👍 Ideally this should've been a part of yari tools like the yarn content macros render command.

@hamishwillee
Copy link
Collaborator

FWIW I can cope with varying whitespace in macros, but line breaks within them grate.

@github-actions github-actions bot added the merge conflicts 🚧 [PR only] label Mar 5, 2024
Copy link
Contributor

github-actions bot commented Mar 5, 2024

This pull request has merge conflicts that must be resolved before it can be merged.

@github-actions github-actions bot removed the merge conflicts 🚧 [PR only] label Mar 5, 2024
@bsmth
Copy link
Member Author

bsmth commented Mar 5, 2024

Thanks, all. Let me break this one down into smaller PRs. @OnkarRuikar, I feel like 7 is too many PRs, however. 4x55 files with 1LoC changed should be digestible, right?

@bsmth bsmth closed this Mar 5, 2024
@wbamberg
Copy link
Collaborator

wbamberg commented Mar 5, 2024

So, I'm sorry to harp on about this, but splitting it up doesn't actually reduce the reviewer workload or the chance that errors would be introduced. One way to frame this is: what are the expectations on reviewers for a PR like this? It contains 220 pages: is the reviewer expected to:

  • open every page in preview
  • find the item generated by the macro
  • check it's properly rendered and working, which for links (which is most of them) means following the link and then adjusting the domain (because preview links don't typically work)

This is a lot of work, and it's very likely that people will make mistakes.

it's a big PR that's quite hard for humans to review reliably (i.e. without introducing new errors). Do we have any confirmation that this PR doesn't add any macro errors? (and produces the exact same output as before?)

In a similar case for formal syntax changes I did complete yari builds of before and after changes. And compared the build directories using a visual diff tool Meld.

Yeah, this is what I had in mind. I think it would be great to smooth the edges for this kind of workflow and make it more common for big cleanup PRs.

if we are going to rely on macros not containing linebreaks, how do we stop them reappearing?

We already have a mechanism in place to lint such custom cases. Following rule in .markdownlint.jsonc should work:

{
"name": "linebreaks-in-macros", 
 "message": "Avoid linebreaks in macro calls", 
 "searchPattern": "/\\{\\{[^{}]*?\n[^{|]*?\\}\\}/g", 
 "searchScope": "text", 
}

The regex may need some tuning.

I'm not so keen on this. We're going to add more complexity to the build, and more fragile regexes, and why? Why is is so important not to break lines in macro calls? I think the answer here is that people want to use grep+regex to find macro invocations, and I'm questioning whether this is the best approach, and whether having more robust tools (e.g. that are based on the KS parser) would work better for us.

@bsmth
Copy link
Member Author

bsmth commented Mar 11, 2024

Thanks for sharing the concerns! As far as introducing errors, the flaw system should flag broken things and I don't see problems being introduced by converting multi-line invocations to single-line invocations. I've already broken this up into smaller PRs which I think are fine to review by looking at the diffs alone. There's no rush to merge any of them as long as these get tidied up eventually.

@hamishwillee
Copy link
Collaborator

FWIW I just reviewed one of these. It was indeed easy to review by inspection. I don't see any problem with converting multi-line invocations to single-line invocations - it is even to my taste. I'd have gone further and removed all arbitrary line breaks.

But we should be pretty clear that while this change isn't risky nor does it really add any concrete value other than to people like me who don't "like" arbitrary line breaks :-). I think if we're going to make these kinds of changes we should put in a process to allow automated output comparision so that minimal human review is required to know that the changes are non-breaking.

Just my two bits.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Content:HTTP HTTP docs Content:JS JavaScript docs Content:WebAPI Web API docs macros Work relating to macro refactoring or removal size/m [PR only] 51-500 LoC changed
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants