Create a dynamic array for use in grunt concat - json

I need to concatenate a set files based on variables I have defined my package.json.
// package.json
...
"layouts": [
{
"page": "home",
"version": "a"
},
{
"page": "about",
"version": "a"
},
{
"page": "contact",
"version": "b"
}
]
...
In grunt I am then building these into a JSON array and pumping it into the src parameter in my grunt-concat-contrib task.
// gruntfile.js
...
var package = grunt.file.readJSON('package.json'),
targets = package.layouts,
paths = [];
for (var target = 0; target < targets.length; target++) {
paths.push("layouts/" + targets[target]['page'] + "/" + targets[target]['version'] + "/*.php");
};
var paths = JSON.stringify(paths);
grunt.log.write(paths); // Writing this to console for debugging
grunt.initConfig({
concat: {
build: {
src: paths,
dest: 'mysite/Code.php',
options: {
separator: '?>\n\n'
}
}
}
});
...
My issue is that the paths variable is not working inside of the initConfig when it is assigned to JSON.stringify(paths).
If I manually input the array like the following that I copied from where I logged the paths variable to the console, it works!
var paths = ["layouts/home/a/*.php","layouts/about/a/*.php","layouts/contact/b/*.php"];
What am I missing?

Derp. I fixed it, I didn't need to JSON.stringify() the array.
Final working gruntfile is below:
// gruntfile.js
...
var package = grunt.file.readJSON('package.json'),
targets = package.layouts,
paths = [];
for (var target = 0; target < targets.length; target++) {
paths.push("layouts/" + targets[target]['page'] + "/" + targets[target]['version'] + "/*.php");
};
grunt.initConfig({
concat: {
build: {
src: paths,
dest: 'mysite/Code.php',
options: {
separator: '?>\n\n'
}
}
}
});
...

Related

Using an variable object inside a Gruntfile

I'm trying to avoid duplicate code by using a variable object inside a Gruntfile with a set of specified parameters. I apologize if this is declared incorrectly, as I'm not entirely sure how to create an object variable in gruntjs. The goal is to use sonarProperties inside the sonarRunner config. In the if block, add some additional lines, and the else block, just use sonarProperties. Unfortunately my syntax is incorrect. Is this even possible? I'm basing it off of a gulpfile and would like to do something similar.
Sample gulpfile:
const packageName = require('./package.json').name;
gulp.task('sonar', callback => {
let sonarProperties = {
// #################################################
// # General Configuration
// #################################################
'sonar.projectKey': `microservice:${packageName}`,
'sonar.sourceEncoding': 'UTF-8',
'sonar.login': process.env.SONAR_TOKEN,
// #################################################
// # Javascript Configuration
// #################################################
'sonar.language': 'javascript',
'sonar.sources': 'src',
'sonar.tests': 'test',
'sonar.javascript.lcov.reportPaths': 'coverage/lcov.info',
'sonar.coverage.exclusions': 'src/**/*.spec.js',
};
if (process.env.SONAR_ANALYSIS_TYPE === 'pr') {
sonarProperties = {
...sonarProperties, // #################################################
// # Github Configuration
// #################################################
'sonar.pullrequest.provider': 'github',
'sonar.pullrequest.branch': process.env.branch,
'sonar.pullrequest.key': process.env.pr_numbers,
'sonar.pullrequest.base': process.env.base_branch,
'sonar.pullrequest.github.repository': process.env.repo,
'sonar.scm.revision': process.env.sha,
};
}
Here's the pertinent points of my gruntfile:
sonarProperties: [{
projectKey: 'microservice:<%= pkg.name %>',
projectName: 'Microservice - <%= pkg.name %>',
sourceEncoding: 'UTF-8',
login: 'admin',
password: 'admin',
host: {
url: 'http://localhost:9000/'
},
language: 'js',
sources: 'js',
tests: 'test',
testExecutionReportPaths: 'test_coverage_reporter/report.xml',
javascript: {
lcov: {
reportPaths: 'test_coverage/lcov.info'
}
},
}],
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
sonarRunner: {
analysis: {
options: {
debug: true,
separator: '\n',
sonar: (function() {
if (process.env.SONAR_ANALYSIS_TYPE === 'pr') {
return {
...sonarProperties
moreParams: someData,
};
} else {
return {
// use just sonarProperties
};
}
}())
}
}
}
});
I was able to create the function with the following:
grunt.registerTask('sonar', function () {
let sonarProperties = {
// #################################################
// # General Configuration
// #################################################
..
}
And declaring it as a callback from the beginning as a grunt task.

Change name of provideCompletionItems command in VsCode Extension

I am creating a VsCode extension which provides inline completions. Currently, it can be accessed using the default "Trigger Suggest" command. I want it to be different, as it should be different from the default option. The main code looks like this:
import * as vscode from 'vscode';
export function activate(context: vscode.ExtensionContext) {
const command = 'getairesponse';
const files = ['c','cpp','csharp','java','javascript', 'php', 'python', 'SQL', 'HTML', 'plaintext'];
const provider1 = vscode.languages.registerCompletionItemProvider(files, {
async provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken, context: vscode.CompletionContext) {
var editor = vscode.window.activeTextEditor;
if (editor){
var cursorPosition = editor.selection.active;
var input = editor.document.getText(new vscode.Range(0, 0, cursorPosition.line, cursorPosition.character));
var out = getOutput(input);
const simpleCompletion = new vscode.CompletionItem(await out);
return [simpleCompletion];
}
}
});
context.subscriptions.push(provider1);
}
I want the command for the extension to be equal to the constant command. I have also included the command in the package.json file:
"contributes": {
"commands": [
{
"command": "getairesponse",
"title": "Get AI Response"
}
]
}

How to prevent duplicates being added to JSON object

Using Electron and electron-store to add files' simplified executable names and their full paths from showOpenDialog to config.json. Selecting the same file causes repeating entries in config.json. For some reason (or rather missing code), app thinks they're different paths.
function addTool() {
dialog.showOpenDialog({
title: 'Select tool executable.',
filters: [{
name: 'Tool start file',
extensions: ['exe', 'jar']
}],
properties: ['openFile']
},
(exeFromDialog) => {
var var_exeToolPath = exeFromDialog.join(); //removes square brackets
var var_toolName = path.basename(var_exeToolPath).split(/[/._-]/g)[0];
//path.basename removes path until file, split+regex takes only first part until first character (one of ._/)
const tools = appConfig.get('tools');
const newTool = [...(tools || []), {
"toolName": var_toolName,
"toolPath": var_exeToolPath
}];
appConfig.set('tools', newTool);
})
}
This is how config.json looks when you open the same file few times:
{
"winPosition": {
"x": 1497,
"y": 410,
"width": 203,
"height": 603
},
"exePOEPath": [
"C:\\Program Files (x86)\\Grinding Gear Games\\Path of Exile\\PathOfExile_x64.exe"
],
"tools": [
{
"toolName": "tool1",
"toolPath": "D:\\tool1.exe"
},
{
"toolName": "tool1",
"toolPath": "D:\\tool1.exe"
},
{
"toolName": "tool1",
"toolPath": "D:\\tool1.exe"
}
]
}
Ultimately it comes to the question How to remove duplicates from your array
This part of your code will always add the new value, it doesn't check for duplicates
const newTool = [...(tools || []), {
toolName: var_toolName,
toolPath: var_exeToolPath
}]
So it should be improved to something like the following:
newTool = newTool.filter((item, pos, self) =>
self.find(other => other.toolName === item.toolName) === item
)
I would prefer using [...new Set([newTool])] but you store Objects which are compared by reference thus duplicates cannot be eliminated by Set

webpack : is there a good hook / custom function to dump out resolved configuration?

I'm somewhat of a newbie with webpack and have been experimenting with easier ways to adjust/merge webpack configurations.
The following code, added to webpack/lib/webpack.js has been pretty helpful:
this is the standard webpack.js:
function webpack(options, callback) {
var compiler;
if(Array.isArray(options)) {
compiler = new MultiCompiler(options.map(function(options) {
return webpack(options);
}));
} else if(typeof options === "object") {
new WebpackOptionsDefaulter().process(options);
compiler = new Compiler();
compiler.options = options;
compiler.options = new WebpackOptionsApply().process(options, compiler);
new NodeEnvironmentPlugin().apply(compiler);
compiler.applyPlugins("environment");
compiler.applyPlugins("after-environment");
} else {
throw new Error("Invalid argument: options");
}
if(callback) {
if(typeof callback !== "function") throw new Error("Invalid argument: callback");
if(options.watch === true || (Array.isArray(options) &&
options.some(function(o) {
return o.watch;
}))) {
var watchOptions = (!Array.isArray(options) ? options : options[0]).watchOptions || {};
// TODO remove this in next major version
var watchDelay = (!Array.isArray(options) ? options : options[0]).watchDelay;
if(watchDelay) {
console.warn("options.watchDelay is deprecated: Use 'options.watchOptions.aggregateTimeout' instead");
watchOptions.aggregateTimeout = watchDelay;
}
return compiler.watch(watchOptions, callback);
}
compiler.run(callback);
}
this is my code:
//customization start
fs = require('fs');
var fnp_dump = 'webpack.dump.json';
fs.writeFile(fnp_dump, JSON.stringify(options, null, 2), function(err) {
if(err) {
return console.log(err);
}
console.log("dumping dump.webpack.js.final.json from webpack.js to: " + fnp_dump);
});
//customization end
return compiler;
}
The basic idea is that it dumps out the final json/js options object after webpack has finished sorting out the usual webpack.base.js + webpack.development.js. Since it's, at that point, just a fully-resolved javascript object, it doesn't really matter how the config.js files were written by individual developers.
Now you can diff options sent to webpack (this is an example of tranforming webpack 1 to webpack 2 configurations:
diff 003/webpack.dump.json 004/webpack.dump.json
< "loader": "style!css!postcss-loader!sass"
---
> "use": [
> {
> "loader": "style-loader"
> },
> {
> "loader": "postcss-loader"
> },
> {
> "loader": "sass-loader"
> }
> ]
However, I am customizing webpack.js directly and need to re-apply my patch after each npm update webpack. Is there a better way?
If your webpack.config.js is a function, you can call it on your own to resolve to an object.
If you have several configs (you mentioned webpack.base.js and webpack.development.js) you can use Webpack Merge to just combine your options to a single object, and then write it to the file system.
I would recommend you to have an own script in package.json to do this job, which you can then always call after your webpack job:
...,
"scripts": {
"dump-options": "scriptThatMergesConfigsAndWritesToFS.js",
"webpack-job": "webpack ... && npm run dump-options",
...
},
...
UPDATE
After some more research I realized, that the resolved options object is stored in the compiler object. The compiler object is passed to Plugins, and therefore you can easily write a Plugin that writes the config to a file, as I did here (not tested).
I also realized, that the Plugins cannot be stringified, as they are functions, so be aware of losing the Plugin configuration information.
I ended up writing my own plugin (and now notice that wtho wrote one too). It worked for me - note you need to have the bit of code that handles circular references:
// WebPackCompilationObserver.js
function WebPackCompilationObserver(options) {
WebPackCompilationObserver.options = options || {};
}
WebPackCompilationObserver.prototype.apply = function(compiler) {
compiler.plugin("emit", function(compilation, callback) {
var fs = require('fs');
var fnp_dump = WebPackCompilationObserver.options.dump_filename;
if (! fnp_dump) {
fnp_dump = "./dump.webpack.options.json";
console.log("please specify dump_filename path in the WebPackCompilationObserver.options, otherwise using default:" % fnp_dump);
}
if (fnp_dump){
console.log("dumping compilation.options to: " + fnp_dump);
var cache = [];
fs.writeFile(fnp_dump, JSON.stringify(compilation.options, function(key, value) {
if (typeof value === 'object' && value !== null) {
if (cache.indexOf(value) !== -1) {
// Circular reference found, discard key
return;
}
// Store value in our collection
cache.push(value);
}
return value;
}, 2),
function(err) {
if (err) {
return console.log(err);
}
});
cache = null;
}
callback();
});
};
module.exports = WebPackCompilationObserver;
To use it:
webpack.config.development.js:
....
var WebPackCompilationObserver = require("./WebPackCompilationObserver");
....
config.plugins = config.plugins.concat([
....
,new WebPackCompilationObserver({dump_filename: '../dumpithere.json'})
])

Exporting jasmine test results in json format from grunt

I am using Jasmine to execute the tests from the Grunt task. I want to output the results from the test cases in JSON. Below is the configuration for the jasmine. This configuration generates XML files under junit folder.
var conf = {
src: [
// '../../../Test.UnitTest.JS/UnitTests/' + name + '/**/*.js'
],
options: {
template: require('grunt-template-jasmine-requirejs'),
templateOptions: {
requireConfig: {
baseUrl: 'SinglePageApplications/' + name,
//waitSeconds: 30,
paths: mixIn({
'knockout-editables': '../../Assets/scripts/vendor/ko.editables-0.9.0',
'knockout-validation': '../../Assets/scripts/vendor/knockout.validation-1.0.2',
'bignumber': '../../Assets/scripts/vendor/bignumber-1.4.1',
'testutils': '../../../Test.UnitTest.JS/Utils',
'shared': '../../Legacy/Shared',
'testdata': '../../../Test.UnitTest.JS/UnitTests/' + name + '/testdata'
}, addConfigurationPaths(app))
}
},
helpers: [
'Assets/scripts/ato/helperscript.js'
],
specs: [
'../Test.UnitTest.JS/UnitTests/' + name + '/**/*.js'
],
junit: {
path: 'build/junit/' + name + '/'
},
timeout: 100000,
vendor: arr
}
,
//specs : 'src/test/js/unit-headless.html',
phantomjs: {
'ignore-ssl-errors': true
}
}
I want the results to be displayed in JSON format so I installed jasmine-json-test-reporter using npm and tried implemented it in my current config like this:
var conf = {
src: [
// '../../../Test.UnitTest.JS/UnitTests/' + name + '/**/*.js'
],
options: {
template: require('grunt-template-jasmine-requirejs'),
templateOptions: {
requireConfig: {
baseUrl: 'SinglePageApplications/' + name,
//waitSeconds: 30,
paths: mixIn({
'knockout-editables': '../../Assets/scripts/vendor/ko.editables-0.9.0',
'knockout-validation': '../../Assets/scripts/vendor/knockout.validation-1.0.2',
'bignumber': '../../Assets/scripts/vendor/bignumber-1.4.1',
'testutils': '../../../Test.UnitTest.JS/Utils',
'shared': '../../Legacy/Shared',
'testdata': '../../../Test.UnitTest.JS/UnitTests/' + name + '/testdata'
}, addConfigurationPaths(app))
}
},
helpers: [
'Assets/scripts/ato/helperscript.js'
//'Legacy/Shared/common/constants.js'
],
specs: [
//'../Test.UnitTest.JS/UnitTests/' + name + '/common/*.js',
//'../Test.UnitTest.JS/UnitTests/' + name + '/testdata',
'../Test.UnitTest.JS/UnitTests/' + name + '/**/*.js'
],
junit: {
path: 'build/junit/' + name + '/'
},
timeout: 100000,
vendor: arr
}
,
//specs : 'src/test/js/unit-headless.html',
phantomjs: {
'ignore-ssl-errors': true
},
onPrepare: function () {
var JSONReporter = require('jasmine-json-test-reporter');
var jasmine = require('jasmine');
return browser.getProcessedConfig().then(function (config) {
browser.params['browsername'] = config.capabilities.browserName.toUpperCase();
browser.params['version'] = config.capabilities.version || 'latest stable';
browser.params['platform'] = config.capabilities.os + '-' + config.capabilities.os_version;
jasmine.getEnv().addReporter(new JSONReporter({
file: 'results/' + browser.params.platform + '-' + browser.params.version + '.' + browser.params.browsername + '.json',
beautify: true,
indentationLevel: 2 // used if beautify === true
}));
});
}
}
This code is not generating any json file. I am not too sure use jasmine-json-test-reporter with current jasmine config.
I manage to get it working. The source files were not point to the right locations. Changing the following lines fixed it:
src: [
'SinglePageApplications/' + name + '/common/**/*.js',
'SinglePageApplications/' + name + '/viewmodels/**/*.js',
'SinglePageApplications/' + name + '/views/**/*.js',
'SinglePageApplications/' + name + '/main.js'
],