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

Babel macro: Add new Babel macro which handles block.json file transformation #16088

Open
wants to merge 4 commits into
base: master
from
Open
Changes from 1 commit
Commits
File filter...
Filter file types
Jump to…
Jump to file or symbol
Failed to load files and symbols.

Always

Just for now

Add translations support to Babel block macro

  • Loading branch information...
gziolo committed Sep 10, 2019
commit c75b3b120b7c387fa3e718c28b9093366d9c79b6

Some generated files are not rendered by default. Learn more.

@@ -6,6 +6,27 @@ const { existsSync, readFileSync } = require( 'fs' );
const { mapKeys, pick } = require( 'lodash' );
const { dirname, join, relative } = require( 'path' );

const aliases = {
styleVariations: 'styles',
};
const whitelistedProperties = [
'name',
'title',
'category',
'parent',
'icon',
'description',
'keywords',
'attributes',
'styles',
];
const translatableProperties = [
'title',
'description',
'keywords',
'styles',
];

function getFilename( [ filenamePath ], state ) {
const filename = filenamePath.evaluate().value;

@@ -26,48 +47,87 @@ function readMetadata( filename ) {
}

function formatMetadata( metadata, types ) {
const aliases = {
styleVariations: 'styles',
};
const replaceWithAlias = ( _, key ) => {
return aliases[ key ] || key;
};
const whitelistedProperties = [
'name',
'title',
'category',
'parent',
'icon',
'description',
'keywords',
'attributes',
'styles',
];

const metadataFiltered = pick(
mapKeys( metadata, replaceWithAlias ),
whitelistedProperties
);
return types.valueToNode( metadataFiltered );
}

const metadataNode = types.valueToNode( metadataFiltered );
/*const translatedProperties = [
'title',
'description',
'keywords',
];*/

return metadataNode;
function wrapTranslatableProperty( node, name, textDomain, types ) {
if ( node.type === 'StringLiteral' ) {
node = types.callExpression(
types.identifier( '_x' ),
[
node,
types.stringLiteral( `block ${ name }` ),
textDomain !== 'default' && types.stringLiteral( textDomain ),
].filter( Boolean )
);
} else if ( node.type === 'ArrayExpression' ) {
node.elements = node.elements.map(
( elementNode ) => wrapTranslatableProperty(
elementNode,
name,
textDomain,
types
)
);
} else if ( node.type === 'ObjectExpression' ) {
node.properties.forEach( ( propertyNode ) => {
if ( propertyNode.key.name === 'label' ) {
propertyNode.value = wrapTranslatableProperty(
propertyNode.value,
name,
textDomain,
types
);
}
} );
}
return node;
}

function babelBlockMacro( { references, state, babel } ) {
const { types } = babel;
references.default.forEach( ( referencePath ) => {
if ( referencePath.parentPath.type === 'CallExpression' ) {
const metadata = readMetadata(
const { textDomain, ...metadata } = readMetadata(
getFilename( referencePath.parentPath.get( 'arguments' ), state )
);

referencePath.parentPath.replaceWith( formatMetadata( metadata, types ) );
if ( textDomain ) {
referencePath.parentPath.node.properties.forEach( ( propertyPath ) => {
if ( translatableProperties.includes( propertyPath.key.name ) ) {
if ( ! state.hasTranslationImportDeclaration ) {
if ( ! referencePath.scope.hasBinding( '_x' ) ) {
const importDeclaration = types.importDeclaration(
[
types.importSpecifier(
types.identifier( '_x' ),
types.identifier( '_x' )
),
],
types.stringLiteral( '@wordpress/i18n' )
);
referencePath.scope.getProgramParent().path
.unshiftContainer( 'body', importDeclaration );
}
state.hasTranslationImportDeclaration = true;
}
propertyPath.value = wrapTranslatableProperty(
propertyPath.value,
propertyPath.key.name,
textDomain,
types
);
}
} );
}
} else {
throw new Error(
`@wordpress/babel-block.macro can only be used as function call. You tried ${ referencePath.parentPath.type }.`,
@@ -27,7 +27,8 @@
],
"main": "index.js",
"dependencies": {
"babel-plugin-macros": "^2.6.1"
"babel-plugin-macros": "^2.6.1",
"lodash": "^4.17.14"
},
"publishConfig": {
"access": "public"
@@ -1,15 +1,75 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`macros valid metadata file name: valid metadata file name 1`] = `
exports[`macros valid metadata file with i18n support and default text domain: valid metadata file with i18n support and default text domain 1`] = `
"
import macro from '../macro';
const metadata = macro( './fixtures/block.json' );
import blockMetadata from '../macro';
const metadata = blockMetadata( './fixtures/block-i18n-default.json' );

↓ ↓ ↓ ↓ ↓ ↓

\\"use strict\\";

var metadata = {
var _i18n = require(\\"@wordpress/i18n\\");

const metadata = {
name: \\"my-plugin/notice\\",
title: (0, _i18n._x)(\\"Notice\\", \\"block title\\", \\"my-plugin\\"),
category: \\"common\\",
description: (0, _i18n._x)(\\"Shows warning, error or success notices ...\\", \\"block description\\", \\"my-plugin\\"),
keywords: [(0, _i18n._x)(\\"alert\\", \\"block keywords\\", \\"my-plugin\\"), (0, _i18n._x)(\\"message\\", \\"block keywords\\", \\"my-plugin\\")],
attributes: {},
styles: [{
name: \\"default\\",
label: (0, _i18n._x)(\\"Default\\", \\"block styles\\", \\"my-plugin\\"),
isDefault: true
}, {
name: \\"other\\",
label: (0, _i18n._x)(\\"Other\\", \\"block styles\\", \\"my-plugin\\")
}]
};
"
`;

exports[`macros valid metadata file with i18n support: valid metadata file with i18n support 1`] = `
"
import blockMetadata from '../macro';
const metadata = blockMetadata( './fixtures/block-i18n.json' );

↓ ↓ ↓ ↓ ↓ ↓

\\"use strict\\";

var _i18n = require(\\"@wordpress/i18n\\");

const metadata = {
name: \\"my-plugin/notice\\",
title: (0, _i18n._x)(\\"Notice\\", \\"block title\\"),
category: \\"common\\",
description: (0, _i18n._x)(\\"Shows warning, error or success notices ...\\", \\"block description\\"),
keywords: [(0, _i18n._x)(\\"alert\\", \\"block keywords\\"), (0, _i18n._x)(\\"message\\", \\"block keywords\\")],
attributes: {},
styles: [{
name: \\"default\\",
label: (0, _i18n._x)(\\"Default\\", \\"block styles\\"),
isDefault: true
}, {
name: \\"other\\",
label: (0, _i18n._x)(\\"Other\\", \\"block styles\\")
}]
};
"
`;

exports[`macros valid metadata file: valid metadata file 1`] = `
"
import blockMetadata from '../macro';
const metadata = blockMetadata( './fixtures/block.json' );

↓ ↓ ↓ ↓ ↓ ↓

\\"use strict\\";

const metadata = {
name: \\"my-plugin/notice\\",
title: \\"Notice\\",
category: \\"common\\",
@@ -0,0 +1,13 @@
{
"name": "my-plugin/notice",
"title": "Notice",
"category": "common",
"description": "Shows warning, error or success notices ...",
"keywords": [ "alert", "message" ],
"textDomain": "my-plugin",
"attributes": {},
"styleVariations": [
{ "name": "default", "label": "Default", "isDefault": true },
{ "name": "other", "label": "Other" }
]
}
@@ -0,0 +1,13 @@
{
"name": "my-plugin/notice",
"title": "Notice",
"category": "common",
"description": "Shows warning, error or success notices ...",
"keywords": [ "alert", "message" ],
"textDomain": "default",
"attributes": {},
"styleVariations": [
{ "name": "default", "label": "Default", "isDefault": true },
{ "name": "other", "label": "Other" }
]
}
@@ -6,7 +6,6 @@
"icon": "star",
"description": "Shows warning, error or success notices ...",
"keywords": [ "alert", "message" ],
"textDomain": "my-plugin",
"attributes": {
"message": {
"type": "string",
@@ -12,31 +12,45 @@ pluginTester( {
presets: [ '@wordpress/babel-preset-default' ],
},
tests: {
'valid metadata file name': {
'valid metadata file': {
code: `
import macro from '../macro';
const metadata = macro( './fixtures/block.json' );
import blockMetadata from '../macro';
const metadata = blockMetadata( './fixtures/block.json' );
`,
snapshot: true,
},
'valid metadata file with i18n support': {
code: `
import blockMetadata from '../macro';
const metadata = blockMetadata( './fixtures/block-i18n.json' );
`,
snapshot: true,
},
'valid metadata file with i18n support and default text domain': {
code: `
import blockMetadata from '../macro';
const metadata = blockMetadata( './fixtures/block-i18n-default.json' );
`,
snapshot: true,
},
'invalid metadata file name': {
code: `
import macro from '../macro';
const metadata = macro( './invalid-file.json' );
import blockMetadata from '../macro';
const metadata = blockMetadata( './invalid-file.json' );
`,
error: 'Invalid file name provided: packages/babel-block.macro/test/invalid-file.json.',
},
'invalid usage: as function argument': {
code: `
import macro from '../macro';
const metadata = doSomething( macro );
import blockMetadata from '../macro';
const metadata = doSomething( blockMetadata );
`,
error: true,
},
'invalid usage: missing file path': {
code: `
import macro from '../macro';
const metadata = macro;
import blockMetadata from '../macro';
const metadata = blockMetadata;
`,
error: true,
},
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.