UNPKG

nativeloop

Version:

⭐ Axway Amplify module for using nativeloop with Appcelerator Titanium SDK Framework

305 lines (260 loc) 10.1 kB
'use strict'; /*** * __ _ __ __ * ____ ___ ____ / /_ (_)/ /___ / /_ ___ _____ ____ * / __ `__ \ / __ \ / __ \ / // // _ \ / __ \ / _ \ / ___// __ \ * / / / / / // /_/ // /_/ // // // __// / / // __// / / /_/ / * /_/ /_/ /_/ \____//_.___//_//_/ \___//_/ /_/ \___//_/ \____/ * * mobile solutions for everyday heroes * * @file Fix resolve issues by replacing functionality * @module @nativeloop/mobile/plugins/resolver/resolver/resolve-fix * @author Brenton House <brenton.house@gmail.com> * @copyright Copyright (c) 2017 by Superhero Studios Incorporated. All Rights Reserved. * @license Licensed under the terms of the MIT License (MIT) * */ var _ = require( 'lodash' ); // var wrench = require( 'wrench' ); var path = require( 'path' ); var fs = require( 'fs-extra' ); var minimatch = require( 'minimatch' ); /** * * @param {string} rootpath - Directory path to start searching for files * @param {object} registry - Object used to store files/modules found * @param {string[]} registry.files - Files found in search * @param {string[]} registry.directories - Directories found in search * @param {object[]} registry.core - Core modules to use in app * @param {object[]} registry.fallback - Modules to use in case of reference to missing module * @param {string[]} [params.includes] - Array of glob patterns to match files to be included in search * @param {object} [logger=console] - Alloy logger object */ module.exports = function( rootpath, registry, includes, logger ) { registry = registry || {}; _.defaults( registry, { files: [], directories: [], core: [], fallback: [], alias: [], } ); logger = logger || console; // logger.debug("includes: " + JSON.stringify(includes, null, 2)); includes = includes || [ '**/*.js', '**/*.json', '!resolver.js' ]; /** * Inject necessary code into the file app.js * @function injectCode */ function injectCode() { var fullpath = path.join( rootpath, "app.js" ); var source = fs.readFileSync( fullpath, 'utf8' ); var test = /\/\/ALLOY-RESOLVER/.test( source ); logger.trace( "CODE INJECTED ALREADY: " + test ); if( !test ) { source = source.replace( /(var\s+Alloy[^;]+;)/g, "$1\n//ALLOY-RESOLVER\nvar process=require('process');\nAlloy.resolve=new (require('nativeloop/resolver'))().resolve;\n" ); fs.writeFileSync( fullpath, source ); } } function fixFile( file ) { var fullpath = path.join( rootpath, file ); var basepath = path.posix.dirname( file ); var basefile = path.posix.resolve( file ); var source = fs.readFileSync( fullpath, 'utf8' ); logger.trace( 'fixing file: ' + fullpath ); var requireRegex = /(require)\s*\(((?:[^)(]+|\((?:[^)(]+|\([^)(]*\))*\))*)\)/g; var staticRequireRegex = /(require)(?:\(\s*['"])([^'"]+)(?:['"]\s*\))/g; var alloyDynamicRegex = /require\(\s*['"]alloy\//g var alloyResolveRegex = /require\(\s*Alloy\.resolve\(/g source = source.replace( requireRegex, function( entireText, requireText, requestedModule ) { // logger.error('entireText: ' + entireText); var isStaticRequire = staticRequireRegex.test( entireText ); var isDynamicAlloyRequire = alloyDynamicRegex.test( entireText ); var isAlloyResolve = alloyResolveRegex.test( entireText ); // logger.trace('isStaticRequire: ' + isStaticRequire); // logger.trace('isDynamicAlloyRequire: ' + isDynamicAlloyRequire); // logger.trace('isAlloyResolve: ' + isAlloyResolve); if( isStaticRequire ) { var revisedText = entireText.replace( staticRequireRegex, function( $1, $2, $3 ) { var resolved_path = resolver.resolve( $3, basepath ); return 'require("' + resolved_path + '")'; } ); // logger.debug('returning: ' + revisedText); return revisedText; } else if( isDynamicAlloyRequire ) { // logger.trace('fixFiles: found dynamic alloy require'); // logger.debug('returning: ' + entireText); return entireText; } else if( isAlloyResolve ) { // logger.trace('fixFiles: found Alloy.resolve require'); // logger.debug('returning: ' + entireText); return entireText; } else { // logger.trace("isDynamicAlloyRequire: " + isDynamicAlloyRequire); // logger.trace("fixFiles: found dynamic non-alloy require"); // logger.debug("returning: " + 'require(Alloy.resolve(' + requestedModule + ', "' + basepath + '"))'); return 'require(Alloy.resolve(' + requestedModule + ', "' + basepath + '"))'; } } ); fs.writeFileSync( fullpath, source, { mode: 0o755 } ); } /** * Fix module resolution in all found javascript files * @function fixFiles */ function fixFiles() { logger.trace( 'inside fixFiles()' ); var filepaths = match( registry.files, includes.concat( [ '!**/*.json' ] ), { nocase: true, matchBase: true, dot: true, } ); _.each( filepaths, fixFile ); } /** * Replace backslashes for cross-platform usage * Adapted from https://github.com/sindresorhus/slash * @function replaceBackSlashes * @param {string} input - value needing to have backslashes replaced in. * @returns {string} */ function replaceBackSlashes( input ) { var isExtendedLengthPath = /^\\\\\?\\/.test( input ); var hasNonAscii = /[^\x00-\x80]+/.test( input ); if( isExtendedLengthPath || hasNonAscii ) { return input; } return input.replace( /\\/g, '/' ); }; /** * Find all files that match extension criteria * @function findFiles * @param {string} rootpath - Absolute path of the directory from which file search will begin * @param {string[]|string} [patterns='**'] - Pattern(s) to be used when attempting to match files found * @returns {string[]} - Matched file paths */ function findFiles( rootpath, patterns ) { // logger.trace('inside findFiles()'); var patterns = patterns || [ '**' ]; if( _.isString( patterns ) ) { patterns = [ patterns ]; } var files = _.map( fs.readdirSyncRecursive( rootpath ), function( filename ) { return path.posix.sep + replaceBackSlashes( filename ); } ); var matchedFiles = match( files, patterns, { nocase: true, matchBase: true, dot: true, } ); return _.filter( matchedFiles, function( file ) { return !fs.statSync( path.join( rootpath, file ) ).isDirectory(); } ) || []; }; /** * Find items in array that match a set of patterns * Adapted from https://github.com/sindresorhus/multimatch * @function match * @param {string[]} [list=[]] * @param {string[]|string} [patterns=[]] * @param {object} [options={}] * @returns {string[]} */ function match( list, patterns, options ) { list = list || []; patterns = patterns || []; if( _.isString( patterns ) ) { patterns = [ patterns ]; } if( list.length === 0 || patterns.length === 0 ) { return []; } options = options || {}; return patterns.reduce( function( ret, pattern ) { var process = _.union if( pattern[ 0 ] === '!' ) { pattern = pattern.slice( 1 ); process = _.difference; } return process( ret, minimatch.match( list, pattern, options ) ); }, [] ); }; /** * Find and process all files * @function loadFiles */ function loadFiles() { // logger.trace('inside loadFiles()'); var allfiles = findFiles( rootpath, [ '**/*.js', '**/*.json' ] ); // logger.debug(JSON.stringify(allfiles, null, 2)); _.forEach( allfiles, function( filepath ) { registry.files.push( filepath ); } ); var packagepaths = _.filter( allfiles, function( filepath ) { return( /.+(package\.json)/.test( filepath ) ); } ); _.forEach( packagepaths, function( filepath ) { var content = fs.readFileSync( path.posix.join( rootpath, filepath ), 'utf8' ); var json = JSON.parse( content ); if( json.main ) { registry.directories.push( { id: path.posix.dirname( filepath ), path: path.posix.resolve( path.posix.join( path.posix.dirname( filepath ), json.main ) ) } ); } } ); var indexpaths = _.filter( allfiles, function( filepath ) { return( /.+(index\.js)/.test( filepath ) ); } ); _.forEach( indexpaths, function( filepath ) { var existingdir = _.find( registry.directories, function( dir ) { return dir.id === path.posix.dirname( filepath ); } ); if( !existingdir ) { registry.directories.push( { id: path.posix.dirname( filepath ), path: filepath } ); } } ); return registry; }; /** * Write registry file to resolver.js * @function writeRegistry */ function writeRegistry() { logger.trace( 'inside writeRegistry()' ); var filepath = path.join( rootpath, resolver.resolve( 'resolver' ) ) + '.js'; var content = fs.readFileSync( filepath, 'utf8' ); var regex = /(var\s+registry\s+=\s+)[^;]*(;)/g; var modified = content.replace( regex, '$1' + JSON.stringify( registry ) + '$2' ); fs.writeFileSync( filepath, modified ); } //fs.copySync(path.join(__dirname, 'lib', 'resolver.js'), path.join(rootpath, 'resolver.js')); // fs.copySync(path.join(__dirname, 'lib', 'path.js'), path.join(rootpath, 'path.js')); // fs.copySync(path.join(__dirname, 'lib', 'process.js'), path.join(rootpath, 'process.js')); //fs.copySync(path.join(__dirname, 'lib', 'alloy', 'lodash.js'), path.join(rootpath, 'alloy', 'lodash.js')); loadFiles(); // var r = require( '../../lib/node_modules/resolver' ); var r = require( '../../lib/resolver' ); var resolver = new r( registry, logger, true ); var registry = resolver.registry; injectCode(); fixFiles(); console.error( 'registry: ' + JSON.stringify( registry, null, 2 ) ); writeRegistry(); // fixFile('/node_modules/nativeloop/resolver.js'); fixFile( '/nativeloop/resolver.js' ); console.error( 'registry: ' + JSON.stringify( registry, null, 2 ) ); Object.defineProperty( this, 'registry', { get: function() { return _.clone( registry ); }, enumerable: true, configurable: false } ); }