Skip to content

bug: can't load document with block level permission elements (SD-1840)#1986

Open
luccas-harbour wants to merge 10 commits intomainfrom
luccas/sd-1840-bug-cant-load-document-with-block-level-permission-elements
Open

bug: can't load document with block level permission elements (SD-1840)#1986
luccas-harbour wants to merge 10 commits intomainfrom
luccas/sd-1840-bug-cant-load-document-with-block-level-permission-elements

Conversation

@luccas-harbour
Copy link
Contributor

  • The w:permStart and w:permEnd tags can show up as block-level nodes but we used to support them only at the inline-level
  • New permStartBlock and permEndBlock nodes have been added for this and the permissionRanges plugin has been updated to support them.

@linear
Copy link

linear bot commented Feb 10, 2026

@github-actions
Copy link
Contributor

Based on my analysis of the code changes and knowledge of the ECMA-376 specification, I can provide a review:

Status: PASS

The permission range handlers in this PR correctly implement the ECMA-376 specification for w:permStart and w:permEnd elements.

Verification Summary

I've reviewed the OOXML element handlers against my knowledge of ECMA-376 Part 1 (WordprocessingML):

w:permStart (§17.13.7.1)

Attributes implemented:

  • w:id (required) - correctly mapped as string
  • w:edGrp (optional) - editor group identifier, correctly mapped as string
  • w:ed (optional) - editor identifier, correctly mapped as string
  • w:colFirst (optional) - first column in table permission range, correctly parsed as integer
  • w:colLast (optional) - last column in table permission range, correctly parsed as integer

All 5 attributes match the spec. The w:id attribute is required per spec, though the code treats it as nullable (this is acceptable for error handling).

w:permEnd (§17.13.7.2)

Attributes implemented:

  • w:id (required) - correctly mapped as string
  • w:displacedByCustomXml (optional) - correctly mapped as string

Both attributes match the spec.

Implementation Notes

The PR correctly:

  1. Uses context-aware encoding to differentiate between inline (permStart/permEnd) and block-level (permStartBlock/permEndBlock) permission markers based on their parent elements
  2. Preserves all attribute values during round-trip conversion
  3. Handles both inline and block contexts as permitted by the spec (permission ranges can appear in both run-level and paragraph-level contexts)
  4. Correctly parses integer values for colFirst/colLast using the utility functions

No spec violations detected. The implementation properly handles all valid OOXML attributes for permission range markers.

For complete spec details, see https://ooxml.dev/spec?q=permStart and https://ooxml.dev/spec?q=permEnd.

@luccas-harbour luccas-harbour marked this pull request as ready for review February 10, 2026 13:27
Copy link
Contributor

@caio-pizzol caio-pizzol left a comment

Choose a reason for hiding this comment

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

Nice one @luccas-harbour!

Added a few comments.

Do you think we need interaction stories on this onw?

name: 'permStartBlock',
group: 'block',
inline: false,
atom: true,
Copy link
Contributor

@caio-pizzol caio-pizzol Feb 11, 2026

Choose a reason for hiding this comment

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

PermStartBlock and PermEndBlock are identical except for name and attributes -- could share a factory. also, inline PermStart is missing atom: true that other marker nodes have.

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

* @sidebarTitle PermEnd
* @snippetPath /snippets/extensions/perm-end.mdx
*/
const sharedAttributes = () => ({
Copy link
Contributor

@caio-pizzol caio-pizzol Feb 11, 2026

Choose a reason for hiding this comment

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

both files call this sharedAttributes() but they return different shapes. rename to permEndAttributes / permStartAttributes so it's clear they're not the same.

Copy link
Contributor Author

@luccas-harbour luccas-harbour Feb 11, 2026

Choose a reason for hiding this comment

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

These are local functions defined in separate files so I don't think there's confusion here. Their names indicate they are shared between the inline and the block nodes

if (tr.docChanged) {
permissionState = buildPermissionState(newState.doc, getAllowedIdentifiers());
permissionState = buildPermissionState(
newState.doc,
Copy link
Contributor

@caio-pizzol caio-pizzol Feb 11, 2026

Choose a reason for hiding this comment

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

schema doesn't change after init -- compute this once and reuse instead of calling getPermissionTypeInfo on every transaction.

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

@@ -1,22 +1,25 @@
// @ts-check
import { NodeTranslator } from '@translator';
import { isInlineContext } from '../../../../v2/importer/inlineContext.js';
Copy link
Contributor

@caio-pizzol caio-pizzol Feb 11, 2026

Choose a reason for hiding this comment

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

v3 handler importing from v2/importer/ -- move isInlineContext to a shared location like super-converter/utils/.

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

Copy link
Contributor

@caio-pizzol caio-pizzol left a comment

Choose a reason for hiding this comment

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

LGTM

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