Skip to content

Commit

Permalink
Merge branch 'master' into fix/autosaves
Browse files Browse the repository at this point in the history
  • Loading branch information
danielbachhuber authored May 31, 2018
2 parents 563a294 + eb4fc18 commit 0bec4ea
Show file tree
Hide file tree
Showing 133 changed files with 2,434 additions and 1,103 deletions.
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
build
build-module
coverage
node_modules
vendor
32 changes: 24 additions & 8 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ module.exports = {
selector: 'ImportDeclaration[source.value=/^@wordpress\\u002F.+\\u002F/]',
message: 'Path access on WordPress dependencies is not allowed.',
},
{
selector: 'ImportDeclaration[source.value=/^blob$/]',
message: 'Use @wordpress/blob as import path instead.',
},
{
selector: 'ImportDeclaration[source.value=/^blocks$/]',
message: 'Use @wordpress/blocks as import path instead.',
Expand All @@ -46,25 +50,29 @@ module.exports = {
selector: 'ImportDeclaration[source.value=/^components$/]',
message: 'Use @wordpress/components as import path instead.',
},
{
selector: 'ImportDeclaration[source.value=/^data$/]',
message: 'Use @wordpress/data as import path instead.',
},
{
selector: 'ImportDeclaration[source.value=/^date$/]',
message: 'Use @wordpress/date as import path instead.',
},
{
selector: 'ImportDeclaration[source.value=/^editor$/]',
message: 'Use @wordpress/editor as import path instead.',
selector: 'ImportDeclaration[source.value=/^deprecated$/]',
message: 'Use @wordpress/deprecated as import path instead.',
},
{
selector: 'ImportDeclaration[source.value=/^element$/]',
message: 'Use @wordpress/element as import path instead.',
selector: 'ImportDeclaration[source.value=/^dom$/]',
message: 'Use @wordpress/dom as import path instead.',
},
{
selector: 'ImportDeclaration[source.value=/^data$/]',
message: 'Use @wordpress/data as import path instead.',
selector: 'ImportDeclaration[source.value=/^editor$/]',
message: 'Use @wordpress/editor as import path instead.',
},
{
selector: 'ImportDeclaration[source.value=/^dom$/]',
message: 'Use @wordpress/dom as import path instead.',
selector: 'ImportDeclaration[source.value=/^element$/]',
message: 'Use @wordpress/element as import path instead.',
},
{
selector: 'ImportDeclaration[source.value=/^utils$/]',
Expand Down Expand Up @@ -102,6 +110,14 @@ module.exports = {
selector: 'CallExpression[callee.name=/^(__|_x|_n|_nx)$/] Literal[value=/\\.{3}/]',
message: 'Use ellipsis character (…) in place of three dots',
},
{
selector: 'ImportDeclaration[source.value="lodash"] Identifier.imported[name="memoize"]',
message: 'Use memize instead of Lodash\'s memoize',
},
{
selector: 'CallExpression[callee.object.name="page"][callee.property.name="waitFor"]',
message: 'Prefer page.waitForSelector instead.'
}
],
},
overrides: [
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Directories/files that may be generated by this project
build
build-module
coverage
/hooks
node_modules
Expand Down
4 changes: 4 additions & 0 deletions CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,7 @@ This list is manually curated to include valuable contributions by volunteers th
| @hblackett |
| @vishalkakadiya |
| @c-shultz |
| @nfmohit-wpmudev |
| @noisysocks | @noisysocks |
| @omarreiss | @omarreiss |
| @hedgefield | @hedgefield |
106 changes: 106 additions & 0 deletions bin/generate-public-grammar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#!/usr/bin/env node
const parser = require( '../node_modules/pegjs/lib/parser.js' );
const fs = require( 'fs' );
const path = require( 'path' );
const grammarSource = fs.readFileSync( './blocks/api/post.pegjs', 'utf8' );
const grammar = parser.parse( grammarSource );

function escape( text ) {
return text
.replace( /\t/g, '\\t' )
.replace( /\r/g, '\\r' )
.replace( /\n/g, '\\n' )
.replace( /\&/g, '&' )
.replace( /</g, '&lt;' );
}

function isGroup( expression ) {
return [
'choice',
'action',
'labeled',
'sequence',
].indexOf( expression.type ) >= 0;
}

function flattenUnary( expression ) {
const shouldWrap = isGroup( expression );
const inner = flatten( expression );
return shouldWrap ? '(' + inner + ')' : inner;
}

function flatten( expression ) {
switch ( expression.type ) {
// Terminal
case 'any':
return '.';
case 'rule_ref':
return expression.name;
case 'literal':
return '"' + escape( expression.value ) + '"';
case 'class':
return (
'[' + ( expression.inverted ? '^' : '' ) +
expression.parts.map( ( part ) =>
escape( Array.isArray( part ) ? part.join( '-' ) : part )
).join( '' ) +
']' + ( expression.ignoreCase ? 'i' : '' )
);

// Unary
case 'zero_or_more':
return flattenUnary( expression.expression ) + '*';
case 'one_or_more':
return flattenUnary( expression.expression ) + '+';
case 'optional':
return flattenUnary( expression.expression ) + '?';
case 'simple_not':
return '!' + flattenUnary( expression.expression );

// Other groups
case 'sequence':
return expression.elements.map( flatten ).join( ' ' );
case 'choice':
const sep = expression.isRuleTop ? '\n / ' : ' / ';
return expression.alternatives.map( flatten ).join( sep );
case 'group':
return '(' + flatten( expression.expression ) + ')';
case 'text':
// Avoid double parentheses
const inner = flatten( expression.expression );
const shouldWrap = inner.indexOf( '(' ) !== 0;
return shouldWrap ? '$(' + inner + ')' : '$' + inner;
case 'action':
case 'labeled':
case 'named':
return flatten( expression.expression );

// Top-level formatting
case 'grammar':
return `<dl>${ expression.rules.map( flatten ).join( '' ) }</dl>`;
case 'rule':
expression.expression.isRuleTop = true;
const displayName = expression.expression.type === 'named' ?
expression.expression.name : '';
return `<dt>${ displayName }</dt>` +
`<dd><pre><header>${ expression.name }</header> = ` +
`${ flatten( expression.expression ) }</pre></dd>`;

default:
throw new Error( JSON.stringify( expression ) );
}
}

fs.writeFileSync(
path.join( __dirname, '..', 'docs', 'grammar.md' ), `
# The Gutenberg block grammar
<style>
dl { display: flex; flex-wrap: wrap; font-size: 110%; }
dt, dd { flex: 40%; margin-bottom: 1em; }
dt { text-align: right; font-style: italic; font-size: 105%; }
dd header { font-weight: bold; }
pre { margin: 0; }
</style>
${ flatten( grammar ) }
` );
124 changes: 124 additions & 0 deletions bin/packages/build.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/**
* script to build WordPress packages into `build/` directory.
*
* Example:
* node ./scripts/build.js
*/

/**
* External Dependenceis
*/
const fs = require( 'fs' );
const path = require( 'path' );
const glob = require( 'glob' );
const babel = require( 'babel-core' );
const chalk = require( 'chalk' );
const mkdirp = require( 'mkdirp' );

/**
* Internal dependencies
*/
const getPackages = require( './get-packages' );
const getBabelConfig = require( './get-babel-config' );

/**
* Module Constants
*/
const PACKAGES_DIR = path.resolve( __dirname, '../../packages' );
const SRC_DIR = 'src';
const BUILD_DIR = {
main: 'build',
module: 'build-module',
};
const DONE = chalk.reset.inverse.bold.green( ' DONE ' );

/**
* Get the package name for a specified file
*
* @param {string} file File name
* @return {string} Package name
*/
function getPackageName( file ) {
return path.relative( PACKAGES_DIR, file ).split( path.sep )[ 0 ];
}

/**
* Get Build Path for a specified file
*
* @param {string} file File to build
* @param {string} buildFolder Output folder
* @return {string} Build path
*/
function getBuildPath( file, buildFolder ) {
const pkgName = getPackageName( file );
const pkgSrcPath = path.resolve( PACKAGES_DIR, pkgName, SRC_DIR );
const pkgBuildPath = path.resolve( PACKAGES_DIR, pkgName, buildFolder );
const relativeToSrcPath = path.relative( pkgSrcPath, file );
return path.resolve( pkgBuildPath, relativeToSrcPath );
}

/**
* Build a file for the required environments (node and ES5)
*
* @param {string} file File path to build
* @param {boolean} silent Show logs
*/
function buildFile( file, silent ) {
buildFileFor( file, silent, 'main' );
buildFileFor( file, silent, 'module' );
}

/**
* Build a file for a specific environment
*
* @param {string} file File path to build
* @param {boolean} silent Show logs
* @param {string} environment Dist environment (node or es5)
*/
function buildFileFor( file, silent, environment ) {
const buildDir = BUILD_DIR[ environment ];
const destPath = getBuildPath( file, buildDir );
const babelOptions = getBabelConfig( environment );

mkdirp.sync( path.dirname( destPath ) );
const transformed = babel.transformFileSync( file, babelOptions ).code;
fs.writeFileSync( destPath, transformed );
if ( ! silent ) {
process.stdout.write(
chalk.green( ' \u2022 ' ) +
path.relative( PACKAGES_DIR, file ) +
chalk.green( ' \u21D2 ' ) +
path.relative( PACKAGES_DIR, destPath ) +
'\n'
);
}
}

/**
* Build the provided package path
*
* @param {string} packagePath absolute package path
*/
function buildPackage( packagePath ) {
const srcDir = path.resolve( packagePath, SRC_DIR );
const files = glob.sync( `${ srcDir }/**/*.js`, {
ignore: `${ srcDir }/**/test/**/*.js`,
nodir: true,
} );

process.stdout.write( `${ path.basename( packagePath ) }\n` );

files.forEach( ( file ) => buildFile( file, true ) );
process.stdout.write( `${ DONE }\n` );
}

const files = process.argv.slice( 2 );

if ( files.length ) {
files.forEach( buildFile );
} else {
process.stdout.write( chalk.inverse( '>> Building packages \n' ) );
getPackages()
.forEach( buildPackage );
process.stdout.write( '\n' );
}
49 changes: 49 additions & 0 deletions bin/packages/get-babel-config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* External dependencies
*/
const { isArray, map } = require( 'lodash' );
const babelPluginTransformReactJSX = require( 'babel-plugin-transform-react-jsx' );
const babelPresetEnv = require( 'babel-preset-env' );

/**
* WordPress dependencies
*/
const babelDefaultConfig = require( '@wordpress/babel-preset-default' );

const plugins = map( babelDefaultConfig.plugins, ( plugin ) => {
if ( isArray( plugin ) && plugin[ 0 ] === babelPluginTransformReactJSX ) {
// TODO: It should become the default value when all modules are moved to packages.
return [ babelPluginTransformReactJSX, { pragma: 'createElement' } ];
}

return plugin;
} );

const babelConfigs = {
main: {
...babelDefaultConfig,
babelrc: false,
plugins,
presets: map( babelDefaultConfig.presets, ( preset ) => {
if ( isArray( preset ) && preset[ 0 ] === babelPresetEnv ) {
return [ babelPresetEnv, Object.assign(
{},
preset[ 1 ],
{ modules: 'commonjs' }
) ];
}
return preset;
} ),
},
module: {
...babelDefaultConfig,
babelrc: false,
plugins,
},
};

function getBabelConfig( environment ) {
return babelConfigs[ environment ];
}

module.exports = getBabelConfig;
24 changes: 24 additions & 0 deletions bin/packages/get-packages.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
* External Dependenceis
*/
const fs = require( 'fs' );
const path = require( 'path' );

/**
* Module Constants
*/
const PACKAGES_DIR = path.resolve( __dirname, '../../packages' );

/**
* Returns the absolute path of all WordPress packages
*
* @return {Array} Package paths
*/
function getPackages() {
return fs
.readdirSync( PACKAGES_DIR )
.map( ( file ) => path.resolve( PACKAGES_DIR, file ) )
.filter( ( f ) => fs.lstatSync( path.resolve( f ) ).isDirectory() );
}

module.exports = getPackages;
Loading

0 comments on commit 0bec4ea

Please sign in to comment.