-
Notifications
You must be signed in to change notification settings - Fork 4.2k
/
apply-block-deprecated-versions.js
124 lines (111 loc) · 4.09 KB
/
apply-block-deprecated-versions.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
/**
* Internal dependencies
*/
import { DEPRECATED_ENTRY_KEYS } from '../constants';
import { validateBlock } from '../validation';
import { getBlockAttributes } from './get-block-attributes';
import { applyBuiltInValidationFixes } from './apply-built-in-validation-fixes';
import { omit } from '../utils';
/**
* Function that takes no arguments and always returns false.
*
* @return {boolean} Always returns false.
*/
function stubFalse() {
return false;
}
/**
* Given a block object, returns a new copy of the block with any applicable
* deprecated migrations applied, or the original block if it was both valid
* and no eligible migrations exist.
*
* @param {import(".").WPBlock} block Parsed and invalid block object.
* @param {import(".").WPRawBlock} rawBlock Raw block object.
* @param {import('../registration').WPBlockType} blockType Block type. This is normalize not necessary and
* can be inferred from the block name,
* but it's here for performance reasons.
*
* @return {import(".").WPBlock} Migrated block object.
*/
export function applyBlockDeprecatedVersions( block, rawBlock, blockType ) {
const parsedAttributes = rawBlock.attrs;
const { deprecated: deprecatedDefinitions } = blockType;
// Bail early if there are no registered deprecations to be handled.
if ( ! deprecatedDefinitions || ! deprecatedDefinitions.length ) {
return block;
}
// By design, blocks lack any sort of version tracking. Instead, to process
// outdated content the system operates a queue out of all the defined
// attribute shapes and tries each definition until the input produces a
// valid result. This mechanism seeks to avoid polluting the user-space with
// machine-specific code. An invalid block is thus a block that could not be
// matched successfully with any of the registered deprecation definitions.
for ( let i = 0; i < deprecatedDefinitions.length; i++ ) {
// A block can opt into a migration even if the block is valid by
// defining `isEligible` on its deprecation. If the block is both valid
// and does not opt to migrate, skip.
const { isEligible = stubFalse } = deprecatedDefinitions[ i ];
if (
block.isValid &&
! isEligible( parsedAttributes, block.innerBlocks, {
blockNode: rawBlock,
block,
} )
) {
continue;
}
// Block type properties which could impact either serialization or
// parsing are not considered in the deprecated block type by default,
// and must be explicitly provided.
const deprecatedBlockType = Object.assign(
omit( blockType, DEPRECATED_ENTRY_KEYS ),
deprecatedDefinitions[ i ]
);
let migratedBlock = {
...block,
attributes: getBlockAttributes(
deprecatedBlockType,
block.originalContent,
parsedAttributes
),
};
// Ignore the deprecation if it produces a block which is not valid.
let [ isValid ] = validateBlock( migratedBlock, deprecatedBlockType );
// If the migrated block is not valid initially, try the built-in fixes.
if ( ! isValid ) {
migratedBlock = applyBuiltInValidationFixes(
migratedBlock,
deprecatedBlockType
);
[ isValid ] = validateBlock( migratedBlock, deprecatedBlockType );
}
// An invalid block does not imply incorrect HTML but the fact block
// source information could be lost on re-serialization.
if ( ! isValid ) {
continue;
}
let migratedInnerBlocks = migratedBlock.innerBlocks;
let migratedAttributes = migratedBlock.attributes;
// A block may provide custom behavior to assign new attributes and/or
// inner blocks.
const { migrate } = deprecatedBlockType;
if ( migrate ) {
let migrated = migrate( migratedAttributes, block.innerBlocks );
if ( ! Array.isArray( migrated ) ) {
migrated = [ migrated ];
}
[
migratedAttributes = parsedAttributes,
migratedInnerBlocks = block.innerBlocks,
] = migrated;
}
block = {
...block,
attributes: migratedAttributes,
innerBlocks: migratedInnerBlocks,
isValid: true,
validationIssues: [],
};
}
return block;
}