mirror of
https://github.com/angular/angular-cli.git
synced 2025-05-17 02:54:21 +08:00
chore(config): ng-config (#506)
This commit is contained in:
parent
8ede7a6897
commit
8ae3cb6d6e
@ -1,3 +1,21 @@
|
||||
{
|
||||
"routes": []
|
||||
}
|
||||
"project": {
|
||||
"version": "<%= version %>",
|
||||
"name": "<%= htmlComponentName %>"
|
||||
},
|
||||
"apps": [
|
||||
{"main": "src/client/main.ts", "tsconfig": "src/client/tsconfig.json"}
|
||||
],
|
||||
"addons": [],
|
||||
"packages": [],
|
||||
"e2e": {
|
||||
"protractor": {
|
||||
"config": "protractor.conf.js"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"karma": {
|
||||
"config": "karma.conf.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
var stringUtils = require('ember-cli/lib/utilities/string');
|
||||
const path = require('path');
|
||||
const stringUtils = require('ember-cli/lib/utilities/string');
|
||||
|
||||
module.exports = {
|
||||
description: '',
|
||||
@ -6,11 +7,13 @@ module.exports = {
|
||||
locals: function(options) {
|
||||
//TODO: pull value from config
|
||||
this.styleExt = 'css';
|
||||
this.version = require(path.resolve(__dirname, '..', '..', '..', '..', 'package.json')).version;
|
||||
|
||||
return {
|
||||
htmlComponentName: stringUtils.dasherize(options.entity.name),
|
||||
jsComponentName: stringUtils.classify(options.entity.name),
|
||||
styleExt: this.styleExt
|
||||
styleExt: this.styleExt,
|
||||
version: this.version
|
||||
};
|
||||
},
|
||||
|
||||
|
@ -6,7 +6,7 @@ import {CliConfig} from '../models/config';
|
||||
const GetCommand = Command.extend({
|
||||
name: 'get',
|
||||
description: 'Set a value in the configuration.',
|
||||
works: 'outsideProject',
|
||||
works: 'everywhere',
|
||||
|
||||
availableOptions: [],
|
||||
|
||||
@ -26,4 +26,3 @@ const GetCommand = Command.extend({
|
||||
});
|
||||
|
||||
module.exports = GetCommand;
|
||||
module.exports.overrideCore = true;
|
||||
|
@ -5,7 +5,7 @@ import {CliConfig} from '../models/config';
|
||||
const SetCommand = Command.extend({
|
||||
name: 'set',
|
||||
description: 'Set a value in the configuration.',
|
||||
works: 'outsideProject',
|
||||
works: 'everywhere',
|
||||
|
||||
availableOptions: [
|
||||
{ name: 'global', type: Boolean, default: false, aliases: ['g'] },
|
||||
@ -22,4 +22,3 @@ const SetCommand = Command.extend({
|
||||
});
|
||||
|
||||
module.exports = SetCommand;
|
||||
module.exports.overrideCore = true;
|
||||
|
@ -1,8 +1,15 @@
|
||||
/* jshint node: true */
|
||||
'use strict';
|
||||
|
||||
const config = require('./models/config');
|
||||
|
||||
module.exports = {
|
||||
name: 'ng2',
|
||||
|
||||
config: function () {
|
||||
this.project.config = this.project.config || config.CliConfig.fromProject();
|
||||
},
|
||||
|
||||
includedCommands: function () {
|
||||
return {
|
||||
'new': require('./commands/new'),
|
||||
|
@ -1,19 +1,16 @@
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
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 interface CliConfigJson {
|
||||
routes?: { [name: string]: any },
|
||||
packages?: { [name: string]: any }
|
||||
}
|
||||
export const ARRAY_METHODS = ['push', 'splice', 'sort', 'reverse', 'pop', 'shift'];
|
||||
|
||||
|
||||
function _findUp(name: string, from: string) {
|
||||
let currentDir = from;
|
||||
while (currentDir && currentDir != '/') {
|
||||
while (currentDir && currentDir !== path.parse(currentDir).root) {
|
||||
const p = path.join(currentDir, name);
|
||||
if (fs.existsSync(p)) {
|
||||
return p;
|
||||
@ -27,9 +24,22 @@ function _findUp(name: string, from: string) {
|
||||
|
||||
|
||||
export class CliConfig {
|
||||
constructor(private _config: CliConfigJson = CliConfig.fromProject()) {}
|
||||
private _config: any;
|
||||
|
||||
save(path: string = CliConfig.configFilePath()) {
|
||||
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 = this._fromProject();
|
||||
}
|
||||
}
|
||||
|
||||
save(path: string = this._configFilePath()) {
|
||||
if (!path) {
|
||||
throw new Error('Could not find config path.');
|
||||
}
|
||||
@ -38,18 +48,55 @@ export class CliConfig {
|
||||
}
|
||||
|
||||
set(jsonPath: string, value: any, force: boolean = false): boolean {
|
||||
let { parent, name, remaining } = this._findParent(jsonPath);
|
||||
while (force && remaining) {
|
||||
if (remaining.indexOf('.') != -1) {
|
||||
// Create an empty map.
|
||||
// TODO: create the object / array based on the Schema of the configuration.
|
||||
parent[name] = {};
|
||||
}
|
||||
|
||||
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('.');
|
||||
}
|
||||
|
||||
parent[name] = value;
|
||||
return true;
|
||||
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 {
|
||||
@ -110,7 +157,7 @@ export class CliConfig {
|
||||
return { parent, name };
|
||||
}
|
||||
|
||||
static configFilePath(projectPath?: string): string {
|
||||
private _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))
|
||||
@ -118,8 +165,8 @@ export class CliConfig {
|
||||
|| _findUp(CLI_CONFIG_FILE_NAME, process.cwd());
|
||||
}
|
||||
|
||||
static fromProject(): CliConfigJson {
|
||||
const configPath = this.configFilePath();
|
||||
private _fromProject(): any {
|
||||
const configPath = this._configFilePath();
|
||||
return configPath ? require(configPath) : {};
|
||||
}
|
||||
}
|
||||
|
@ -96,5 +96,8 @@ module.exports = function(options) {
|
||||
// ensure the environemnt variable for dynamic paths
|
||||
process.env.PWD = process.env.PWD || process.cwd();
|
||||
|
||||
|
||||
process.env.CLI_ROOT = process.env.CLI_ROOT || path.resolve(__dirname, '..', '..');
|
||||
|
||||
return cli(options);
|
||||
}
|
||||
|
@ -22,7 +22,7 @@
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"root": "string",
|
||||
"main": "string",
|
||||
"tsconfig": "string"
|
||||
},
|
||||
"additionalProperties": false
|
||||
|
85
tests/models/config.spec.ts
Normal file
85
tests/models/config.spec.ts
Normal file
@ -0,0 +1,85 @@
|
||||
import {CliConfig} from '../../addon/ng2/models/config';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
const expect = require('chai').expect;
|
||||
const config = path.resolve(process.cwd(), 'addon/ng2/blueprints/ng2/files/angular-cli.json');
|
||||
const configCopy = path.resolve(process.cwd(), 'angular-cli.json');
|
||||
|
||||
function getContents() {
|
||||
return require(configCopy);
|
||||
}
|
||||
|
||||
describe('Config Tests', () => {
|
||||
before(() => {
|
||||
process.chdir(process.cwd());
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
let contents = JSON.parse(fs.readFileSync(config, 'utf8'));
|
||||
fs.writeFileSync(configCopy, JSON.stringify(contents, null, 2), 'utf8');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
try {
|
||||
fs.accessSync(configCopy);
|
||||
fs.unlinkSync(configCopy);
|
||||
} catch (e) { /* */ }
|
||||
});
|
||||
|
||||
it('Throws an error if config file not exists', () => {
|
||||
fs.unlinkSync(configCopy);
|
||||
|
||||
let fn = () => {
|
||||
return new CliConfig('foobar.json');
|
||||
}
|
||||
|
||||
expect(fn).to.throw(Error);
|
||||
});
|
||||
|
||||
it('Updates property of type `string` successfully', () => {
|
||||
let c = new CliConfig(configCopy);
|
||||
c.set('project.name', 'new-project-name');
|
||||
c.save();
|
||||
|
||||
let contents = getContents();
|
||||
|
||||
expect(contents).to.be.an('object');
|
||||
expect(contents.project.name).to.exist;
|
||||
expect(contents.project.name).to.be.equal('new-project-name');
|
||||
});
|
||||
|
||||
it('Throws an error if try to assign property that does not exists', () => {
|
||||
let c = new CliConfig(configCopy);
|
||||
|
||||
let fn = () => {
|
||||
c.set('project.foo', 'bar');
|
||||
c.save();
|
||||
}
|
||||
|
||||
expect(fn).to.throw(Error);
|
||||
});
|
||||
|
||||
it('Throws an error if try to use array method on property of type `string`', () => {
|
||||
let c = new CliConfig(configCopy);
|
||||
|
||||
let fn = () => {
|
||||
c.set('project.name.push', 'new-project-name');
|
||||
c.save();
|
||||
}
|
||||
|
||||
expect(fn).to.throw(Error);
|
||||
});
|
||||
|
||||
it('Throws an error if try to use `number` on property of type `string`', () => {
|
||||
let c = new CliConfig(configCopy);
|
||||
|
||||
let fn = () => {
|
||||
c.set('project.name', 42);
|
||||
c.save();
|
||||
}
|
||||
|
||||
expect(fn).to.throw(Error);
|
||||
});
|
||||
|
||||
});
|
@ -1,12 +1,45 @@
|
||||
/* eslint-disable no-console */
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
const ts = require('typescript');
|
||||
const old = require.extensions['.ts'];
|
||||
|
||||
require.extensions['.ts'] = function(m, filename) {
|
||||
if (!filename.match(/angular-cli/) && filename.match(/node_modules/)) {
|
||||
if (old) {
|
||||
return old(m, filename);
|
||||
}
|
||||
return m._compile(fs.readFileSync(filename), filename);
|
||||
}
|
||||
|
||||
const source = fs.readFileSync(filename).toString();
|
||||
|
||||
try {
|
||||
const result = ts.transpile(source, {
|
||||
target: ts.ScriptTarget.ES5,
|
||||
module: ts.ModuleKind.CommonJs
|
||||
});
|
||||
|
||||
// Send it to node to execute.
|
||||
return m._compile(result, filename);
|
||||
} catch (err) {
|
||||
console.error('Error while running script "' + filename + '":');
|
||||
console.error(err.stack);
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
var Mocha = require('mocha');
|
||||
var glob = require('glob');
|
||||
var path = require('path');
|
||||
|
||||
var root = 'tests/{unit,acceptance,e2e}';
|
||||
var specFiles = glob.sync(root + '/**/*.spec.js');
|
||||
var root = 'tests/{acceptance,models,e2e}';
|
||||
var specFiles = glob.sync(root + '/**/*.spec.*');
|
||||
var mocha = new Mocha({ timeout: 5000, reporter: 'spec' });
|
||||
|
||||
process.env.CLI_ROOT = process.env.CLI_ROOT || path.resolve(__dirname, '..');
|
||||
|
||||
specFiles.forEach(mocha.addFile.bind(mocha));
|
||||
|
||||
mocha.run(function (failures) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user