Skip to content

feat(install): 1. and 3. phase from design docs #294

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 6 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
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
addon/ng2/blueprints/ng2/files/src/config/system.config.js
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we want to ignore that single file? It seems like it should be linted.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because of the double quotes which are mandatory for JSON.parse in systemjs-helper.ts.

2 changes: 1 addition & 1 deletion addon/ng2/blueprints/ng2/files/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,6 @@
"ts-node": "^0.5.5",
"tslint": "^3.6.0",
"typescript": "^1.8.7",
"typings": "^0.6.6"
"typings": "^0.7.7"
}
}
8 changes: 8 additions & 0 deletions addon/ng2/blueprints/ng2/files/src/config/system.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
System.config({
"packages": {
"app": {
"format": "register",
"defaultExtension": "js"
}
}
});
9 changes: 1 addition & 8 deletions addon/ng2/blueprints/ng2/files/src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,8 @@
<script src="vendor/angular2/bundles/http.dev.js"></script>
<script src="vendor/angular2/bundles/router.dev.js"></script>

<script src="config/system.config.js"></script>
<script>
System.config({
packages: {
app: {
format: 'register',
defaultExtension: 'js'
}
}
});
System.import('app.js').then(null, console.error.bind(console));
</script>
</body>
Expand Down
30 changes: 30 additions & 0 deletions addon/ng2/commands/install.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import * as Command from 'ember-cli/lib/models/command';
import * as SlientError from 'silent-error';
import * as InstallTask from '../tasks/install';

module.exports = Command.extend({
name: 'install',
description: 'Adds 3rd party library to existing project',
works: 'insideProject',

run: function (commandOptions, rawArgs) {
if (!rawArgs.length) {
const msg = 'The `ng install` command must take an argument with ' +
'a package name.';

return Promise.reject(new SilentError(msg));
}

const installTask = new InstallTask({
ui: this.ui,
analytics: this.analytics,
project: this.project
});

return installTask.run({
packages: rawArgs
});
}
});

module.exports.overrideCore = true;
30 changes: 30 additions & 0 deletions addon/ng2/commands/uninstall.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import * as Command from 'ember-cli/lib/models/command';
import * as SilentError from 'silent-error';
import * as UninstallTask from '../tasks/uninstall';

module.exports = Command.extend({
name: 'uninstall',
description: 'Removes 3rd party library from existing project',
works: 'insideProject',

run: function (commandOptions, rawArgs) {
if (!rawArgs.length) {
const msg = 'The `ng uninstall` command must take an argument with ' +
'a package name.';

return Promise.reject(new SilentError(msg));
}

const uninstallTask = new UninstallTask({
ui: this.ui,
analytics: this.analytics,
project: this.project
});

return uninstallTask.run({
packages: rawArgs
});
}
});

module.exports.overrideCore = true;
4 changes: 3 additions & 1 deletion addon/ng2/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ module.exports = {
'format': require('./commands/format'),
'version': require('./commands/version'),
'completion': require('./commands/completion'),
'doc': require('./commands/doc')
'doc': require('./commands/doc'),
'install': require('./commands/install'),
'uninstall': require('./commands/uninstall')
};
}
};
101 changes: 101 additions & 0 deletions addon/ng2/tasks/install.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import * as Task from 'ember-cli/lib/models/task';
import * as npmTask from 'ember-cli/lib/tasks/npm-task';
import * as chalk from 'chalk';
import * as path from 'path';
import { EventEmitter } from 'events';
import * as search from 'typings-core/dist/search';
import * as typings from 'typings-core/dist/install';
import * as systemJS from '../utilities/systemjs-helper';

module.exports = Task.extend({
completionOKMessage: 'Successfully installed.',
completionErrorMessage: 'Error installing package.',

run: function(options) {
this.packages = options.packages;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused as to what this does. Could you explain it? Preferably in a comment.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It gets object with data from install command, I just name it options in case we'll add something later, currently is just the packages it gets from arguments.


if (this.packages.indexOf('sass') !== -1) {
this.packages[this.packages.indexOf('sass')] = 'node-sass';
}

if (this.packages.indexOf('compass') !== -1) {
this.packages[this.packages.indexOf('compass')] = 'compass-importer';
if (this.packages.indexOf('sass') === -1 || this.packages.indexOf('node-sass')) {
this.packages.push('node-sass');
}
}

return this.installProcedure();
},

installProcedure: function() {
const that = this;

const NpmTask = new npmTask({
command: 'install',
ui: this.ui,
analytics: this.analytics,
project: this.project,
startProgressMessage: 'Installing packages: ' + this.packages,
completionMessage: 'Packages successfully installed.'
});

return NpmTask.run({
packages: this.packages,
verbose: false
})
.then(() => this.storeInSystemJSConfig(this.packages))
.then(() => this.installTypings());
},

installTypings: function() {
this.ui.startProgress(chalk.green('Searching and installing typings'), chalk.green('.'));
this.packages = this.packages.filter(p => !/node-sass|stylus|less|compass-importer/.test(p));

let typingsList = [];

return Promise.all(this.packages.map(p => {
return new Promise(res => {
search.search({ name: p }).then(resp => {
if (resp.results.length) {
let names = resp.results.map(x => {
if (x.source === 'dt') { return x.name; }
}).filter(x => !!x);
typingsList = typingsList.concat(names);
}
res();
});
});
}))
.then(() => {
return Promise.all(typingsList.map(t => {
return new Promise(res => {
let installOpts = { cwd: process.env.PWD, save: true, ambient: true };
typings.installDependencyRaw(t, installOpts).then(() => { res(); });
});
}))
.then(() => {
return this.ui.stopProgress();
})
});
},

storeInSystemJSConfig: function(packages) {
const systemPath = path.resolve(process.cwd(), 'src', 'config', 'system.config.js');
let json = systemJS.loadSystemJson(systemPath);

packages = packages.filter(p => {
return (!/node-sass|stylus|less|compass-importer/.test(p));
});

let mappings = json.map || {};
packages.forEach(pkg => {
mappings[pkg] = 'libs/' + pkg + '/' + pkg + '.js';
});
json.map = mappings;
systemJS.saveSystemJson(systemPath, json);

return Promise.resolve();
}

});
81 changes: 81 additions & 0 deletions addon/ng2/tasks/uninstall.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import * as Task from 'ember-cli/lib/models/task';
import * as npmTask from 'ember-cli/lib/tasks/npm-task';
import * as chalk from 'chalk';
import * as path from 'path';
import * as search from 'typings-core/dist/search';
import * as typings from 'typings-core/dist/uninstall';
import * as systemJS from '../utilities/systemjs-helper';

module.exports = Task.extend({
run: function(options) {
this.packages = options.packages;

return this.uninstallProcedure();
},

uninstallProcedure: function() {
const that = this;

const NpmTask = new npmTask({
command: 'uninstall',
ui: this.ui,
analytics: this.analytics,
project: this.project,
startProgressMessage: 'Uninstalling packages: ' + this.packages,
completionMessage: 'Packages successfully uninstalled.'
});

return NpmTask.run({
packages: this.packages,
verbose: false
})
.then(() => this.removeFromSystemJSConfig(this.packages))
.then(() => this.uninstallTypings());
},

uninstallTypings: function() {
this.ui.startProgress(chalk.green('Uninstalling typings'), chalk.green('.'));
this.packages = this.packages.filter(p => !/node-sass|stylus|less|compass-importer/.test(p));
let typingsList = [];

return Promise.all(this.packages.map(p => {
return new Promise(res => {
search.search({ name: p }).then(resp => {
if (resp.results.length) {
let names = resp.results.map(x => {
if (x.source === 'dt') { return x.name; }
}).filter(x => !!x);
typingsList = typingsList.concat(names);
}
res();
});
});
}))
.then(() => {
return Promise.all(typingsList.map(t => {
return new Promise(res => {
let installOpts = { cwd: process.env.PWD, save: true, ambient: true };
typings.uninstallDependency(t, installOpts).then(() => { res(); });
});
}))
.then(() => {
return this.ui.stopProgress();
})
});
},

removeFromSystemJSConfig: function(packages) {
const systemPath = path.resolve(process.cwd(), 'src', 'config', 'system.config.js');

let json = systemJS.loadSystemJson(systemPath);
let mappings = json.map || {};
packages.forEach(pkg => {
delete mappings[pkg];
});
json.map = mappings;
systemJS.saveSystemJson(systemPath, json);

return Promise.resolve();
}

});
16 changes: 16 additions & 0 deletions addon/ng2/utilities/systemjs-helper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/// <reference path="../../../typings/main.d.ts" />
import fs = require('fs');

export function loadSystemJson(systemPath: string): { [name: string]: any } {
const systemContents: any = fs.readFileSync(systemPath, 'utf8');
const jsonContent: any = systemContents.match(/^[^\{]*([\s\S]+)\);.*$/m)[1];

return JSON.parse(jsonContent);
}

export function saveSystemJson(systemPath: string, json: { [name: string]: any }) {
const jsonContent: any = JSON.stringify(json, null, '\t');
const writeContents: any = 'System.config(' + jsonContent + ');';

fs.writeFileSync(systemPath, writeContents, 'utf8');
}
79 changes: 79 additions & 0 deletions lib/broccoli/angular-broccoli-compass.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/* jshint node: true, esversion: 6 */
'use strict';

try {
let sass;
let compass;

if (process.platform === 'win32') {
require.resolve(`${process.env.PWD}/node_modules/node-sass`);
require.resolve(`${process.env.PWD}/node_modules/compass-importer`);
sass = require(`${process.env.PWD}/node_modules/node-sass`);
compass = require(`${process.env.PWD}/node_modules/compass-importer`);
} else {
process.env.NODE_PATH += `:${process.env.PWD}/node_modules`;
require('module').Module._initPaths();
require.resolve('node-sass');
require.resolve('compass-importer');
sass = require('node-sass');
compass = require('compass-importer');
}

const Plugin = require('broccoli-caching-writer');
const fse = require('fs-extra');
const path = require('path');
const Funnel = require('broccoli-funnel');

class CompassPlugin extends Plugin {
constructor(inputNodes, options) {
super(inputNodes, {});

options = options || {};
Plugin.call(this, inputNodes, {
cacheInclude: [/(.*?).scss$/, /(.*?).sass$/]
});
this.options = options;
this.fileRegistry = [];
}

build() {
let entries = this.listEntries();
let rootFileNames = entries.map(e => {
return path.resolve(e.basePath, e.relativePath);
});

rootFileNames.forEach(fileName => {
this.compile(fileName, this.inputPaths[0], this.outputPath);
});
}

compile(fileName, inputPath, outputPath) {
let sassOptions = {
file: path.join(fileName),
includePaths: this.inputPaths,
data: '@import "compass"; .transition { @include transition(all); }',
importer: compass
};

let result = sass.renderSync(sassOptions);
let filePath = fileName.replace(inputPath, outputPath)
.replace(/\.scss$/, '.css')
.replace(/\.sass$/, '.css');

fse.outputFileSync(filePath, result.css, 'utf8');
}
}

exports.makeBroccoliTree = (sourceDir) => {
let compassSrcTree = new Funnel(sourceDir, {
include: ['**/*.scss', '**/*.sass'],
allowEmpty: true
});

return new CompassPlugin([compassSrcTree]);
};
} catch (e) {
exports.makeBroccoliTree = () => {
return null;
};
}
Loading