Skip to content

Feature/628 starterkit config #632

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

Closed
wants to merge 2 commits into from
Closed
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
3 changes: 2 additions & 1 deletion core/lib/patternlab.js
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,8 @@ var patternlab_engine = function (config) {
}

function loadStarterKit(starterkitName, clean) {
var starterkit_manager = new sm(patternlab.config);
const configPath = path.resolve(process.cwd(), 'patternlab-config.json');
const starterkit_manager = new sm(patternlab.config, configPath);
starterkit_manager.load_starterkit(starterkitName, clean);
}

Expand Down
98 changes: 83 additions & 15 deletions core/lib/starterkit_manager.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,72 @@
"use strict";

var starterkit_manager = function (config) {
var path = require('path'),
fetch = require('node-fetch'),
fs = require('fs-extra'),
util = require('./utilities'),
paths = config.paths;
// needs to be mutable for "rewire"
let fs = require('fs-extra');
let path = require('path');

const fetch = require('node-fetch');
const util = require('./utilities');
const _ = require('lodash');

const starterkit_manager = function (config, configPath) {
const paths = config.paths;

/**
* Ovewrites any values in the Pattern Lab config file with values from starterkit-config.json.
* If no starterkit configuration exists, nothing will be done.
*
* @param starterKitRoot
*/
function updateConfig(starterKitRoot) {

let starterKitRootStats;
try {
starterKitRootStats = fs.statSync(starterKitRoot);
} catch (ex) {
util.error(starterKitRoot + ' not found, please use npm to install it first.');
util.error(starterKitRoot + ' not loaded.');
return;
}
if (starterKitRootStats.isDirectory()) {

const diskConfig = fs.readJSONSync(path.resolve(configPath), 'utf8');
const starterKitConfig = path.resolve(starterKitRoot, 'starterkit-config.json');
let success = true;
try {
const starterKitConfigJSON = fs.readJSONSync(starterKitConfig, 'utf8');

// Idea: Merge objects so that paths and templateExtension can be changed
// Also overwrite arrays instead of appending to them
// Use case:
// "ignored-extensions" : ["scss", "DS_Store", "less"],
// "ignored-directories" : ["less"],

// Attention: If the array contains any objects, it gets replaced completely!
_.mergeWith(diskConfig, starterKitConfigJSON, (target, source) => {
if (_.isArray(source)) {
return source;
}

// Delegate to default behaviour
return undefined;
});

} catch (ex) {
//a starterkit-config.json file is not required at this time
success = false;
}

//write config entry back
// Also used for unit testing the result...
fs.outputFileSync(path.resolve(configPath), JSON.stringify(diskConfig, null, 2));

// Only output if we changed some values so users are not confused
// We want to tell the user that something was changed
if (success) {
console.log("Using starterkit-config.json to update patternlab-config.json");
}
}
}

/**
* Loads npm module identified by the starterkitName parameter.
Expand All @@ -15,19 +76,25 @@ var starterkit_manager = function (config) {
*/
function loadStarterKit(starterkitName, clean) {
try {
var kitPath = path.resolve(
path.join(process.cwd(), 'node_modules', starterkitName, config.starterkitSubDir)
const kitRoot = path.resolve(
path.join(process.cwd(), 'node_modules', starterkitName)
);
const kitPath = path.resolve(
path.join(kitRoot, config.starterkitSubDir)
);
console.log('Attempting to load starterkit from', kitPath);
let kitRootStats;
let kitDirStats;

try {
var kitDirStats = fs.statSync(kitPath);
kitRootStats = fs.statSync(kitRoot);
kitDirStats = fs.statSync(kitPath);
} catch (ex) {
util.error(starterkitName + ' not found, please use npm to install it first.');
util.error(starterkitName + ' not loaded.');
return;
}
var kitPathDirExists = kitDirStats.isDirectory();
if (kitPathDirExists) {
if (kitDirStats.isDirectory() && kitRootStats.isDirectory()) {

if (clean) {
console.log('Deleting contents of', paths.source.root, 'prior to starterkit load.');
Expand All @@ -42,6 +109,7 @@ var starterkit_manager = function (config) {
util.error(ex);
return;
}
updateConfig(kitRoot);
util.debug('starterkit ' + starterkitName + ' loaded successfully.');
}
} catch (ex) {
Expand All @@ -61,7 +129,7 @@ var starterkit_manager = function (config) {
'Accept': 'application/json'
}
}).then(function (res) {
var contentType = res.headers.get('content-type');
const contentType = res.headers.get('content-type');
if (contentType && contentType.indexOf('application/json') === -1) {
throw new TypeError("StarterkitManager->listStarterkits: Not valid JSON");
}
Expand Down Expand Up @@ -90,9 +158,9 @@ var starterkit_manager = function (config) {
* @return {array} List of starter kits installed
*/
function detectStarterKits() {
var node_modules_path = path.join(process.cwd(), 'node_modules');
var npm_modules = fs.readdirSync(node_modules_path).filter(function (dir) {
var module_path = path.join(process.cwd(), 'node_modules', dir);
const node_modules_path = path.join(process.cwd(), 'node_modules');
const npm_modules = fs.readdirSync(node_modules_path).filter(function (dir) {
const module_path = path.join(process.cwd(), 'node_modules', dir);
return fs.statSync(module_path).isDirectory() && dir.indexOf('starterkit-') === 0;
});
return npm_modules;
Expand Down
2 changes: 1 addition & 1 deletion core/scripts/postinstall.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ try {
var config = fs.readJSONSync(path.resolve(configPath), 'utf8');

//determine if any starterkits are already installed
var starterkit_manager = new sm(config);
var starterkit_manager = new sm(config, configPath);
var foundStarterkits = starterkit_manager.detect_starterkits();

//todo - enhance to support multiple kits with prompt for each or all
Expand Down
139 changes: 139 additions & 0 deletions test/starterkit_manager_tests.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
"use strict";
const tap = require('tap');
const path = require('path');
const rewire = require('rewire');

// eslint-disable-next-line no-unused-vars
const fs = require('fs-extra');


let config = {
"not": "overwritten",
"patternExtension": "mustache",
"anArray": ["foo", "bar"],
"nestedObject": {
"foo": 1,
"bar": "original"
},
"paths": {"source": {"root": "./source/"} }
};

tap.test("StarterKit configuration works as excepted", function (test) {
const starterkit_manager = rewire('../core/lib/starterkit_manager');

//set up a global mocks - we don't want to be writing/rendering any files right now
const fsMock = {
readJSONSync: function (thePath) {
if (thePath.endsWith("patternlab-config.json")) {

return config;
}

if (thePath.endsWith("starterkit-config.json")) {
return {
"patternExtension": "html",
"anArray": ["baz"],
"nestedObject": {
"bar": "overwritten"
},
"newField": "value"
};
}
throw "Never happens";
},
copySync: function () {

},
statSync: function () {
return {
isDirectory: function () {
return true;
}
};
},
outputFileSync: function (file, data) {
test.same(
JSON.parse(data), {
"not": "overwritten",
"patternExtension": "html",
"anArray": ["baz"],
"nestedObject": {
"foo": 1,
"bar": "overwritten"
},
"paths": {"source": {"root": "./source/"}},
"newField": "value"
}, "The configuration is overwritten correctly"
);
}
};

//set our mocks in place of usual require()
starterkit_manager.__set__({
'fs': fsMock,
'path': {
resolve: function () {
return Array.prototype.slice.call(arguments).join(path.sep);
},
join: function () {
return Array.prototype.slice.call(arguments).join(path.sep);
}
}
});

const sm = new starterkit_manager(config, "patternlab-config.json");
sm.load_starterkit("starterkit-foo", false);
test.end();
});



tap.test("StarterKit configuration is not mandatory", function (test) {
const starterkit_manager = rewire('../core/lib/starterkit_manager');
const starterkitConfig = "starterkit-config.json";

//set up a global mocks - we don't want to be writing/rendering any files right now
const fsMock = {
readJSONSync: function (thePath) {
if (thePath.endsWith("patternlab-config.json")) {
return config;
}
if (thePath.endsWith(starterkitConfig)) {
throw new Error("File does not exist");
}
throw "Never happens";
},
copySync: function () { },
statSync: function (file) {
if (file === starterkitConfig) {
throw new Error("File does not exist");
}
return {
isDirectory: function () {
return true;
}
};
},
outputFileSync: function (file, data) {
// config is not modified when file does not exist
test.same(JSON.parse(data), config, "The configuration is overwritten correctly");
}
};

//set our mocks in place of usual require()
starterkit_manager.__set__({
'fs': fsMock,
'path': {
resolve: function () {
return Array.prototype.slice.call(arguments).join(path.sep);
},
join: function () {
return "";
}
}
});

const sm = new starterkit_manager(config, "patternlab-config.json");
sm.load_starterkit("starterkit-foo", false);
test.end();
});