Skip to content
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
4 changes: 3 additions & 1 deletion addon/ng2/commands/get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ const GetCommand = Command.extend({

run: function (commandOptions, rawArgs): Promise<void> {
return new Promise(resolve => {
const value = new CliConfig().get(rawArgs[0]);
const config = CliConfig.fromProject();
const value = config.get(rawArgs[0]);

if (value === null) {
console.error(chalk.red('Value cannot be found.'));
} else if (typeof value == 'object') {
Expand Down
10 changes: 5 additions & 5 deletions addon/ng2/commands/github-pages-deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ module.exports = Command.extend({
type: String,
default: 'new gh-pages version',
description: 'The commit message to include with the build, must be wrapped in quotes.'
}, {
}, {
name: 'target',
type: String,
default: 'production',
default: 'production',
aliases: ['t', { 'dev': 'development' }, { 'prod': 'production' }]
}, {
}, {
name: 'environment',
type: String,
default: '',
Expand Down Expand Up @@ -72,12 +72,12 @@ module.exports = Command.extend({
}
if (options.target === 'production') {
options.environment = 'prod';
}
}
}

var projectName = this.project.pkg.name;

const outDir = CliConfig.fromProject().apps[0].outDir;
const outDir = CliConfig.fromProject().config.apps[0].outDir;

let ghPagesBranch = 'gh-pages';
let destinationBranch = options.userPage ? 'master' : ghPagesBranch;
Expand Down
33 changes: 31 additions & 2 deletions addon/ng2/commands/set.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import * as SilentError from 'silent-error';
import * as Command from 'ember-cli/lib/models/command';
import {CliConfig} from '../models/config';

Expand All @@ -11,10 +12,38 @@ const SetCommand = Command.extend({
{ name: 'global', type: Boolean, default: false, aliases: ['g'] },
],

asBoolean: function (raw: string): boolean {
if (raw == 'true' || raw == '1') {
return true;
} else if (raw == 'false' || raw == '' || raw == '0') {
return false;
} else {
throw new SilentError(`Invalid boolean value: "${raw}"`);
}
},
asNumber: function (raw: string): number {
if (Number.isNaN(+raw)) {
throw new SilentError(`Invalid number value: "${raw}"`);
}
return +raw;
},

run: function (commandOptions, rawArgs): Promise<void> {
return new Promise(resolve => {
const config = new CliConfig();
config.set(rawArgs[0], rawArgs[1], commandOptions.force);
const [jsonPath, rawValue] = rawArgs;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

rawValue should just be value, no need for let value = rawValue; in line 36.

Copy link
Copy Markdown
Contributor Author

@hansl hansl Aug 24, 2016

Choose a reason for hiding this comment

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

rawValue is const, and of type string.
value is non-const, and of type any.

const config = CliConfig.fromProject();
const type = config.typeOf(jsonPath);
let value: any = rawValue;

switch (type) {
case 'boolean': value = this.asBoolean(rawValue); break;
case 'number': value = this.asNumber(rawValue); break;
case 'string': value = rawValue; break;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is this newline intended?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Basically between options and default. I can remove if you like.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No need, just wanted to be sure it was intended.

default: value = JSON.parse(rawValue);
}

config.set(jsonPath, value);
config.save();
resolve();
});
Expand Down
4 changes: 2 additions & 2 deletions addon/ng2/commands/test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as TestCommand from 'ember-cli/lib/commands/test';
import * as config from '../models/config';
import * as TestTask from '../tasks/test';
import {CliConfig} from '../models/config';

module.exports = TestCommand.extend({
availableOptions: [
Expand All @@ -14,7 +14,7 @@ module.exports = TestCommand.extend({
],

run: function (commandOptions) {
this.project.ngConfig = this.project.ngConfig || config.CliConfig.fromProject();
this.project.ngConfig = this.project.ngConfig || CliConfig.fromProject();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Should be || CliConfig.fromProject().config; I think.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Actually this is correct. We use ngConfig.config everywhere where it's needed. I do think config is a misnomer and might be better off as root, but I have to refactor some usage of this anyway. That might happen later on (with Feenix).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

But won't it break other commands if they are run in sequence? Everything else expects this.project.ngConfig to have config instead.

Or the other way around, if nothing else breaks by having one command assign the wrong thing to this.project.ngConfig, maybe this is unnecessary.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Weird, I thought I saw this being attributed loads of times.. but it's only in index.js now that I double check. My bad.


var testTask = new TestTask({
ui: this.ui,
Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion addon/ng2/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ module.exports = {
name: 'ng2',

config: function () {
this.project.ngConfig = this.project.ngConfig || config.CliConfig.fromProject();
this.project.ngConfig = this.project.ngConfig || config.CliConfig.fromProject().config;
},

includedCommands: function () {
Expand Down
169 changes: 21 additions & 148 deletions addon/ng2/models/config.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import {CliConfig as CliConfigBase} from './config/config';
import {CliConfig as ConfigInterface} from '../../../lib/config/schema';
import * as chalk from 'chalk';
import * as fs from 'fs';
import * as path from 'path';
import * as chalk from 'chalk';

const schemaPath = path.resolve(process.env.CLI_ROOT, 'lib/config/schema.json');
const schema = require(schemaPath);

export const CLI_CONFIG_FILE_NAME = 'angular-cli.json';
export const ARRAY_METHODS = ['push', 'splice', 'sort', 'reverse', 'pop', 'shift'];


function _findUp(name: string, from: string) {
let currentDir = from;
Expand All @@ -16,175 +18,46 @@ function _findUp(name: string, from: string) {
return p;
}

currentDir = path.resolve(currentDir, '..');
currentDir = path.dirname(currentDir);
}

return null;
}


export class CliConfig {
private _config: any;

constructor(path?: string) {
if (path) {
try {
fs.accessSync(path);
this._config = require(path);
} catch (e) {
throw new Error(`Config file does not exits.`);
}
} else {
this._config = CliConfig.fromProject();
}
}

save(path: string = CliConfig._configFilePath()) {
if (!path) {
throw new Error('Could not find config path.');
}

fs.writeFileSync(path, JSON.stringify(this._config, null, 2), { encoding: 'utf-8' });
}

set(jsonPath: string, value: any, force: boolean = false): boolean {
let method: any = null;
let splittedPath = jsonPath.split('.');
if (ARRAY_METHODS.indexOf(splittedPath[splittedPath.length - 1]) != -1) {
method = splittedPath[splittedPath.length - 1];
splittedPath.splice(splittedPath.length - 1, 1);
jsonPath = splittedPath.join('.');
}

let { parent, name, remaining } = this._findParent(jsonPath);
let properties: any;
let additionalProperties: boolean;

const checkPath = jsonPath.split('.').reduce((o, i) => {
if (!o || !o.properties) {
throw new Error(`Invalid config path.`);
}
properties = o.properties;
additionalProperties = o.additionalProperties;

return o.properties[i];
}, schema);
const configPath = jsonPath.split('.').reduce((o, i) => o[i], this._config);

if (!properties[name] && !additionalProperties) {
throw new Error(`${name} is not a known property.`);
}

if (method) {
if (Array.isArray(configPath) && checkPath.type === 'array') {
[][method].call(configPath, value);
return true;
} else {
throw new Error(`Trying to use array method on non-array property type.`);
}
}

if (typeof checkPath.type === 'string' && isNaN(value)) {
parent[name] = value;
return true;
}

if (typeof checkPath.type === 'number' && !isNaN(value)) {
parent[name] = value;
return true;
}

if (typeof value != checkPath.type) {
throw new Error(`Invalid value type. Trying to set ${typeof value} to ${path.type}`);
}
}

get(jsonPath: string): any {
let { parent, name, remaining } = this._findParent(jsonPath);
if (remaining || !(name in parent)) {
return null;
} else {
return parent[name];
}
}

private _validatePath(jsonPath: string) {
if (!jsonPath.match(/^(?:[-_\w\d]+(?:\[\d+\])*\.)*(?:[-_\w\d]+(?:\[\d+\])*)$/)) {
throw `Invalid JSON path: "${jsonPath}"`;
}
}

private _findParent(jsonPath: string): { parent: any, name: string | number, remaining?: string } {
this._validatePath(jsonPath);

let parent: any = null;
let current: any = this._config;

const splitPath = jsonPath.split('.');
let name: string | number = '';

while (splitPath.length > 0) {
const m = splitPath.shift().match(/^(.*?)(?:\[(\d+)\])*$/);

name = m[1];
const index: string = m[2];
parent = current;
current = current[name];

if (current === null || current === undefined) {
return {
parent,
name,
remaining: (!isNaN(index) ? `[${index}]` : '') + splitPath.join('.')
};
}

if (!isNaN(index)) {
name = index;
parent = current;
current = current[index];

if (current === null || current === undefined) {
return {
parent,
name,
remaining: splitPath.join('.')
};
}
}
}
function getUserHome() {
return process.env[(process.platform == 'win32') ? 'USERPROFILE' : 'HOME'];
}

return { parent, name };
}

export class CliConfig extends CliConfigBase<ConfigInterface> {
private static _configFilePath(projectPath?: string): string {
// Find the configuration, either where specified, in the angular-cli project
// (if it's in node_modules) or from the current process.
return (projectPath && _findUp(CLI_CONFIG_FILE_NAME, projectPath))
|| _findUp(CLI_CONFIG_FILE_NAME, __dirname)
|| _findUp(CLI_CONFIG_FILE_NAME, process.cwd());
|| _findUp(CLI_CONFIG_FILE_NAME, process.cwd())
|| _findUp(CLI_CONFIG_FILE_NAME, __dirname);
}

public static fromProject(): any {
const configPath = CliConfig._configFilePath();

static fromProject(): CliConfig {
const configPath = this._configFilePath();
const globalConfigPath = path.join(getUserHome(), CLI_CONFIG_FILE_NAME);

if (!configPath) {
return {};
}

let config = require(configPath);

if (config.defaults.sourceDir || config.defaults.prefix) {
config.apps[0].root = config.apps[0].root || config.defaults.sourceDir;
config.apps[0].prefix = config.apps[0].prefix || config.defaults.prefix;

const cliConfig = CliConfigBase.fromConfigPath(CliConfig._configFilePath(), [globalConfigPath]);
if (cliConfig.alias('apps.0.root', 'defaults.sourceDir')
+ cliConfig.alias('apps.0.prefix', 'defaults.prefix')) {
console.error(chalk.yellow(
'The "defaults.prefix" and "defaults.sourceDir" properties of angular-cli.json '
'The "defaults.prefix" and "defaults.sourceDir" properties of angular-cli.json\n'
+ 'are deprecated in favor of "apps[0].root" and "apps[0].prefix".\n'
+ 'Please update in order to avoid errors in future versions of angular-cli.'
));
}
return config;

return cliConfig as CliConfig;
}
}
Loading