这是indexloc提供的服务,不要输入任何密码
Skip to content

Add theme init script #28

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

Merged
merged 15 commits into from
Apr 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
313 changes: 313 additions & 0 deletions bin/init.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,313 @@
#! /usr/bin/env node

/* eslint no-console: 0 */

/**
* External dependencies
*/
const fs = require( 'fs' );
const path = require( 'path' );
const readline = require( 'readline' );

/**
* Define Constants
*/
const rl = readline.createInterface( {
input: process.stdin,
output: process.stdout,
} );
const info = {
error: ( message ) => {
return `\x1b[31m${ message }\x1b[0m`;
},
success: ( message ) => {
return `\x1b[32m${ message }\x1b[0m`;
},
warning: ( message ) => {
return `\x1b[33m${ message }\x1b[0m`;
},
message: ( message ) => {
return `\x1b[34m${ message }\x1b[0m`;
},
};
let fileContentUpdated = false;
let fileNameUpdated = false;

// Start with a prompt.
rl.question( 'Would you like to setup the theme? (y/n) ', ( answer ) => {
if ( 'n' === answer.toLowerCase() ) {
console.log( info.warning( '\nTheme Setup Cancelled.\n' ) );
process.exit( 0 );
}
rl.question( 'Enter theme name (shown in WordPress admin)*: ', ( themeName ) => {
const themeInfo = setupTheme( themeName );
rl.question( 'Confirm the Theme Details (y/n) ', ( confirm ) => {
if ( 'n' === confirm.toLowerCase() ) {
console.log( info.warning( '\nTheme Setup Cancelled.\n' ) );
process.exit( 0 );
}
initTheme( themeInfo );
rl.close();
} );
} );
} );

rl.on( 'close', () => {
process.exit( 0 );
} );

/**
* Theme Setup
*
* @param {string} themeName
*
* @return {Object} themeInfo
*/
const setupTheme = ( themeName ) => {
console.log( info.success( '\nFiring up the theme setup...' ) );

// Ask theme name.
if ( ! themeName ) {
console.log( info.error( '\nTheme name is required.\n' ) );
process.exit( 0 );
}

// Generate theme info.
const themeInfo = generateThemeInfo( themeName );

const themeDetails = {
'Theme Name: ': `${ themeInfo.themeName }`,
'Theme Version: ': `1.0.0`,
'Text Domain: ': `${ themeInfo.kebabCase }`,
'Package: ': `${ themeInfo.trainCase }`,
'Namespace: ': `${ themeInfo.pascalSnakeCase }`,
'Function Prefix: ': `${ themeInfo.snakeCaseWithUnderscoreSuffix }`,
'CSS Class Prefix: ': `${ themeInfo.kebabCaseWithHyphenSuffix }`,
'PHP Variable Prefix: ': `${ themeInfo.snakeCaseWithUnderscoreSuffix }`,
'Version Constant: ': `${ themeInfo.macroCase }_VERSION`,
'Theme Directory Constant: ': `${ themeInfo.macroCase }_TEMP_DIR`,
'Theme Build Directory Constant: ': `${ themeInfo.macroCase }_BUILD_DIR`,
'Theme Build Directory URI Constant: ': `${ themeInfo.macroCase }_BUILD_URI`,
};

const biggestStringLength = themeDetails[ 'Theme Build Directory URI Constant: ' ].length + 'Theme Build Directory URI Constant: '.length;

console.log( info.success( '\nTheme Details:' ) );
console.log(
info.warning( '┌' + '─'.repeat( biggestStringLength + 2 ) + '┐' ),
);
Object.keys( themeDetails ).forEach( ( key ) => {
console.log(
info.warning( '│' + ' ' + info.success( key ) + info.message( themeDetails[ key ] ) + ' ' + ' '.repeat( biggestStringLength - ( themeDetails[ key ].length + key.length ) ) + info.warning( '│' ) ),
);
} );
console.log(
info.warning( '└' + '─'.repeat( biggestStringLength + 2 ) + '┘' ),
);

return themeInfo;
};

/**
* Initialize new theme
*
* @param {Object} themeInfo
*/
const initTheme = ( themeInfo ) => {
const chunksToReplace = {
'elementary theme': themeInfo.themeNameLowerCase,
'Elementary Theme': themeInfo.themeName,
'ELEMENTARY THEME': themeInfo.themeNameCobolCase,
'elementary-theme': themeInfo.kebabCase,
'Elementary-Theme': themeInfo.trainCase,
'ELEMENTARY-THEME': themeInfo.cobolCase,
elementary_theme: themeInfo.snakeCase,
Elementary_Theme: themeInfo.pascalSnakeCase,
ELEMENTARY_THEME: themeInfo.macroCase,
'elementary-theme-': themeInfo.kebabCaseWithHyphenSuffix,
'Elementary-Theme-': themeInfo.trainCaseWithHyphenSuffix,
'ELEMENTARY-THEME-': themeInfo.cobolCaseWithHyphenSuffix,
elementary_theme_: themeInfo.snakeCaseWithUnderscoreSuffix,
Elementary_Theme_: themeInfo.pascalSnakeCaseWithUnderscoreSuffix,
ELEMENTARY_THEME_: themeInfo.macroCaseWithUnderscoreSuffix,
};

const files = getAllFiles( getRoot() );

// File name to replace in.
const fileNameToReplace = {};
files.forEach( ( file ) => {
const fileName = path.basename( file );
Object.keys( chunksToReplace ).forEach( ( key ) => {
if ( fileName.includes( key ) ) {
fileNameToReplace[ fileName ] = fileName.replace( key, chunksToReplace[ key ] );
}
} );
} );

// Replace files contents.
console.log( info.success( '\nUpdating theme details in file(s)...' ) );
Object.keys( chunksToReplace ).forEach( ( key ) => {
replaceFileContent( files, key, chunksToReplace[ key ] );
} );
if ( ! fileContentUpdated ) {
console.log( info.error( 'No file content updated.\n' ) );
}

// Replace file names
console.log( info.success( '\nUpdating theme file(s) name...' ) );
Object.keys( fileNameToReplace ).forEach( ( key ) => {
replaceFileName( files, key, fileNameToReplace[ key ] );
} );
if ( ! fileNameUpdated ) {
console.log( info.error( 'No file name updated.\n' ) );
}

if ( fileContentUpdated || fileNameUpdated ) {
console.log( info.success( '\nYour new theme is ready to go!' ), '✨' );
// Docs link
console.log( info.success( '\nFor more information on how to use this theme, please visit the following link: ' + info.warning( 'https://github.com/rtCamp/theme-elementary/blob/main/README.md' ) ) );
} else {
console.log( info.warning( '\nNo changes were made to your theme.\n' ) );
}
};

/**
* Get all files in a directory
*
* @param {Array} dir - Directory to search
*/
const getAllFiles = ( dir ) => {
const dirOrFilesIgnore = [
'.git',
'.github',
'node_modules',
'vendor',
'init.js',
];

try {
let files = fs.readdirSync( dir );
files = files.filter( ( fileOrDir ) => ! dirOrFilesIgnore.includes( fileOrDir ) );

const allFiles = [];
files.forEach( ( file ) => {
const filePath = path.join( dir, file );
const stat = fs.statSync( filePath );
if ( stat.isDirectory() ) {
allFiles.push( ...getAllFiles( filePath ) );
} else {
allFiles.push( filePath );
}
} );
return allFiles;
} catch ( err ) {
console.log( info.error( err ) );
}
};

/**
* Replace content in file
*
* @param {Array} files Files to search
* @param {string} chunksToReplace String to replace
* @param {string} newChunk New string to replace with
*/
const replaceFileContent = ( files, chunksToReplace, newChunk ) => {
files.forEach( ( file ) => {
const filePath = path.resolve( getRoot(), file );

try {
let content = fs.readFileSync( filePath, 'utf8' );
const regex = new RegExp( chunksToReplace, 'g' );
content = content.replace( regex, newChunk );
if ( content !== fs.readFileSync( filePath, 'utf8' ) ) {
fs.writeFileSync( filePath, content, 'utf8' );
console.log( info.success( `Updated [${ info.message( chunksToReplace ) }] ${ info.success( 'to' ) } [${ info.message( newChunk ) }] ${ info.success( 'in file' ) } [${ info.message( path.basename( file ) ) }]` ) );
fileContentUpdated = true;
}
} catch ( err ) {
console.log( info.error( `\nError: ${ err }` ) );
}
} );
};

/**
* Change File Name
*
* @param {Array} files Files to search
* @param {string} oldFileName Old file name
* @param {string} newFileName New file name
*/
const replaceFileName = ( files, oldFileName, newFileName ) => {
files.forEach( ( file ) => {
if ( oldFileName !== path.basename( file ) ) {
return;
}
const filePath = path.resolve( getRoot(), file );
const newFilePath = path.resolve( getRoot(), file.replace( oldFileName, newFileName ) );
try {
fs.renameSync( filePath, newFilePath );
console.log( info.success( `Updated file [${ info.message( path.basename( filePath ) ) }] ${ info.success( 'to' ) } [${ info.message( path.basename( newFilePath ) ) }]` ) );
fileNameUpdated = true;
} catch ( err ) {
console.log( info.error( `\nError: ${ err }` ) );
}
} );
};

/**
* Generate Theme Info from Theme Name
*
* @param {string} themeName
*/
const generateThemeInfo = ( themeName ) => {
const themeNameLowerCase = themeName.toLowerCase();

const kebabCase = themeName.replace( /\s+/g, '-' ).toLowerCase();
const snakeCase = kebabCase.replace( /\-/g, '_' );
const kebabCaseWithHyphenSuffix = kebabCase + '-';
const snakeCaseWithUnderscoreSuffix = snakeCase + '_';

const trainCase = kebabCase.replace( /\b\w/g, ( l ) => {
return l.toUpperCase();
} );
const themeNameTrainCase = trainCase.replace( /\-/g, ' ' );
const pascalSnakeCase = trainCase.replace( /\-/g, '_' );
const trainCaseWithHyphenSuffix = trainCase + '-';
const pascalSnakeCaseWithUnderscoreSuffix = pascalSnakeCase + '_';

const cobolCase = kebabCase.toUpperCase();
const themeNameCobolCase = themeNameTrainCase.toUpperCase();
const macroCase = snakeCase.toUpperCase();
const cobolCaseWithHyphenSuffix = cobolCase + '-';
const macroCaseWithUnderscoreSuffix = macroCase + '_';

return {
themeName,
themeNameLowerCase,
kebabCase,
snakeCase,
kebabCaseWithHyphenSuffix,
snakeCaseWithUnderscoreSuffix,
trainCase,
themeNameTrainCase,
pascalSnakeCase,
trainCaseWithHyphenSuffix,
pascalSnakeCaseWithUnderscoreSuffix,
cobolCase,
themeNameCobolCase,
macroCase,
cobolCaseWithHyphenSuffix,
macroCaseWithUnderscoreSuffix,
};
};

/**
* Return root directory
*
* @return {string} root directory
*/
const getRoot = () => {
return path.resolve( __dirname, '../' );
};
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "rtcamp/theme-elementary",
"name": "rtcamp/elementary-theme",
"description": "A Block based starter theme.",
"type": "wordpress-theme",
"homepage": "https://rtcamp.com/",
Expand Down Expand Up @@ -28,7 +28,7 @@
},
"autoload-dev": {
"psr-4": {
"Elementary\\Tests\\": "tests/php/"
"Elementary_Theme\\Tests\\": "tests/php/"
}
},
"scripts": {
Expand Down
28 changes: 14 additions & 14 deletions functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,37 +4,37 @@
*
* @link https://developer.wordpress.org/themes/basics/theme-functions/
*
* @package Elementary
* @package Elementary-Theme
*/

if ( ! defined( 'ELEMENTARY_VERSION' ) ) :
define( 'ELEMENTARY_VERSION', wp_get_theme()->get( 'Version' ) );
if ( ! defined( 'ELEMENTARY_THEME_VERSION' ) ) :
define( 'ELEMENTARY_THEME_VERSION', wp_get_theme()->get( 'Version' ) );
endif;

if ( ! defined( 'ELEMENTARY_TEMP_DIR' ) ) :
define( 'ELEMENTARY_TEMP_DIR', untrailingslashit( get_template_directory() ) );
if ( ! defined( 'ELEMENTARY_THEME_TEMP_DIR' ) ) :
define( 'ELEMENTARY_THEME_TEMP_DIR', untrailingslashit( get_template_directory() ) );
endif;

if ( ! defined( 'ELEMENTARY_BUILD_URI' ) ) :
define( 'ELEMENTARY_BUILD_URI', untrailingslashit( get_template_directory_uri() ) . '/assets/build' );
if ( ! defined( 'ELEMENTARY_THEME_BUILD_URI' ) ) :
define( 'ELEMENTARY_THEME_BUILD_URI', untrailingslashit( get_template_directory_uri() ) . '/assets/build' );
endif;

if ( ! defined( 'ELEMENTARY_BUILD_DIR' ) ) :
define( 'ELEMENTARY_BUILD_DIR', untrailingslashit( get_template_directory() ) . '/assets/build' );
if ( ! defined( 'ELEMENTARY_THEME_BUILD_DIR' ) ) :
define( 'ELEMENTARY_THEME_BUILD_DIR', untrailingslashit( get_template_directory() ) . '/assets/build' );
endif;

require_once ELEMENTARY_TEMP_DIR . '/vendor/autoload.php';
require_once ELEMENTARY_THEME_TEMP_DIR . '/vendor/autoload.php';

/**
* Theme bootstrap instance.
*
* @since 1.0.0
*
* @return object Elementary
* @return object Theme bootstrap instance.
*/
function elementary_instance() {
return Elementary\Elementary::get_instance();
function elementary_theme_instance() {
return Elementary_Theme\Elementary_Theme::get_instance();
}

// Instantiate theme.
elementary_instance();
elementary_theme_instance();
Loading