Skip to content
This repository has been archived by the owner on Feb 18, 2019. It is now read-only.

Commit

Permalink
feat(dtsm): implement link sub command refs #9
Browse files Browse the repository at this point in the history
  • Loading branch information
vvakame committed May 10, 2015
1 parent ca8e832 commit 4141749
Show file tree
Hide file tree
Showing 8 changed files with 258 additions and 9 deletions.
10 changes: 9 additions & 1 deletion dtsm.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,15 @@
}
],
"path": "typings",
"bundle": null,
"bundle": "./typings/bundle.d.ts",
"link": {
"npm": {
"include": true
},
"bower": {
"include": true
}
},
"dependencies": {
"update-notifier/update-notifier.d.ts": {
"ref": "557bb595af0ab301d098fb5bd50943fffbfcee57"
Expand Down
43 changes: 42 additions & 1 deletion lib/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,9 @@ root
.then(manager=> {
if (!opts.interactive && args.files.length === 0) {
return manager.installFromFile({dryRun: opts.dryRun})
.then(result => printResult(result));
.then(result => printResult(result))
.then(()=> manager.link({dryRun: opts.dryRun}))
.then(result => printLinkResult(result));
} else if (opts.interactive || args.files.length === 0) {
return manager.search("")
.then(resultList => {
Expand Down Expand Up @@ -229,6 +231,25 @@ root
.catch(errorHandler);
});

interface LinkOptions {
save:boolean;
dryRun: boolean;
}

root
.subCommand<LinkOptions, {}>("link")
.description("link to npm or bower dependencies")
.option("--save", "save updated ref into dtsm.json")
.option("--dry-run", "save .d.ts file path into dtsm.json")
.action((opts, args)=> {
setup(root.parsedOpts)
.then(manager=> {
return manager.link({save: opts.save, dryRun: opts.dryRun});
})
.then(result => printLinkResult(result))
.catch(errorHandler);
});

root
.subCommand<{}, {}>("refs")
.description("show refs, it can use with --ref option")
Expand Down Expand Up @@ -392,6 +413,26 @@ function printResult(result:pmb.Result) {
});
}

function printLinkResult(resultList:dtsm.LinkResult[]) {
"use strict";

["npm", "bower"].forEach(managerName => {
let npmList = resultList.filter(result => result.managerName === managerName);
if (npmList.length !== 0) {
let d:archy.Data = {
label: `from ${managerName} dependencies`,
nodes: npmList.map(dep => {
return {
label: dep.depName,
nodes: dep.files
};
})
};
console.log(archy(d));
}
});
}

function errorHandler(err:any) {
"use strict";

Expand Down
2 changes: 2 additions & 0 deletions lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,7 @@ export import Manager = ma.Manager;
import m = require("./model");
export import Options = m.Options;
export import Recipe = m.Recipe;
export import Link = m.Link;
export import LinkResult = m.LinkResult;
export import GlobalConfig = m.GlobalConfig;
/* tslint:enable:no-unused-variable */
103 changes: 97 additions & 6 deletions lib/manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ export class Manager {
this.savedRecipe.repos = this.savedRecipe.repos || this.repos;
this.savedRecipe.path = this.savedRecipe.path || this.path;
this.savedRecipe.bundle = typeof this.savedRecipe.bundle !== "undefined" ? this.savedRecipe.bundle : this.bundle; // for this.recipe.bundle === null
this.savedRecipe.link = this.savedRecipe.link || {};
this.savedRecipe.link["npm"] = this.savedRecipe.link["npm"] || {include: true};
this.savedRecipe.dependencies = this.savedRecipe.dependencies || {};
}

Expand Down Expand Up @@ -321,7 +323,7 @@ export class Manager {
if (!recipe.bundle) {
return;
}
this._addReferenceToBundle(recipe, depResult.depName);
this._addReferenceToBundle(recipe, _path.relative(this.path, depResult.depName));
});

return result;
Expand Down Expand Up @@ -476,6 +478,95 @@ export class Manager {
});
}

link(opts:{ save?: boolean; dryRun?: boolean }):Promise<m.LinkResult[]> {
this.tracker.track("link");

if (!this.configPath) {
return Promise.reject<m.LinkResult[]>("configPath is required");
}
this._setupDefaultRecipe();
if (!this.savedRecipe.bundle) {
return Promise.reject<m.LinkResult[]>("bundle is required");
}

let linkInfo = this.savedRecipe.link || {};
let resultList:m.LinkResult[] = [];
{
let depInfo = this._processLink(linkInfo["npm"], "npm", "package.json", "node_modules");
linkInfo["npm"] = depInfo.link;
if (!opts || !opts.dryRun) {
depInfo.results.forEach(r => {
r.files.forEach(filePath => {
this._addReferenceToBundle(this.savedRecipe, filePath);
});
});
}
resultList = resultList.concat(depInfo.results);
}
{
let depInfo = this._processLink(linkInfo["bower"], "bower", "bower.json", "bower_components");
linkInfo["bower"] = depInfo.link;
if (!opts || !opts.dryRun) {
depInfo.results.forEach(r => {
r.files.forEach(filePath => {
this._addReferenceToBundle(this.savedRecipe, filePath);
});
});
}
resultList = resultList.concat(depInfo.results);
}
this.savedRecipe.link = linkInfo;
if (opts && opts.save) {
this._save();
}

return Promise.resolve(resultList);
}

_processLink(linkInfo:m.Link, managerName:string, configFileName:string, moduleDir:string):{ link: m.Link; results: m.LinkResult[]; } {
if (linkInfo == null) {
// continue
} else if (!linkInfo.include) {
return {link: linkInfo, results: []};
}
linkInfo = linkInfo || {include: true};
let definitionList:m.LinkResult[] = [];
let configPath = _path.join(_path.dirname(this.configPath), linkInfo.configPath || configFileName);
if (!fs.existsSync(configPath)) {
return {link: linkInfo, results: []};
}

let configData = JSON.parse(fs.readFileSync(configPath, {encoding: "utf8"}));
["dependencies", "devDependencies"].forEach(propName => {
Object.keys(configData[propName] || {}).forEach(depName => {
let depConfigPath = _path.join(_path.dirname(configPath), moduleDir, depName, configFileName);
if (!fs.existsSync(depConfigPath)) {
return;
}
let depConfig = JSON.parse(fs.readFileSync(depConfigPath, {encoding: "utf8"}));
let definitionInfo = depConfig["typescript"];
if (!definitionInfo) {
return;
}
let resultList:string[] = [];
["definition", "definitions"].forEach(propName => {
if (typeof definitionInfo[propName] === "string") {
resultList.push(definitionInfo[propName]);
} else if (Array.isArray(definitionInfo[propName])) {
resultList = resultList.concat(definitionInfo[propName]);
}
});
definitionList.push({
managerName: managerName,
depName: depName,
files: resultList.map(filePath => _path.join(_path.dirname(configPath), moduleDir, depName, filePath))
});
});
});

return {link: linkInfo, results: definitionList};
}

_writeDefinitionFile(recipe:m.Recipe, depResult:pmb.ResolvedDependency) {
var path = _path.resolve(_path.dirname(this.configPath), recipe.path, depResult.depName);
mkdirp.sync(_path.resolve(path, "../"));
Expand All @@ -495,17 +586,17 @@ export class Manager {
}
}

_addReferenceToBundle(recipe:m.Recipe, depName:string) {
_addReferenceToBundle(recipe:m.Recipe, pathFromCwd:string) {
var bundleContent = "";
var bundlePath = _path.resolve(_path.dirname(this.configPath), recipe.bundle);
var bundlePath = _path.join(_path.dirname(this.configPath), recipe.bundle);
if (fs.existsSync(bundlePath)) {
bundleContent = fs.readFileSync(bundlePath, "utf8");
} else {
mkdirp.sync(_path.resolve(bundlePath, "../"));
mkdirp.sync(_path.dirname(bundlePath));
}
var referencePath = _path.relative(_path.resolve(recipe.bundle, "../"), _path.resolve(recipe.path, depName));
var referencePath = _path.relative(_path.dirname(bundlePath), pathFromCwd);
if (_path.posix) {
referencePath = _path.posix.relative(_path.posix.resolve(recipe.bundle, "../"), _path.posix.resolve(recipe.path, depName));
referencePath = _path.posix.relative(_path.posix.dirname(bundlePath), pathFromCwd);
}
var referenceComment = "/// <reference path=\"" + referencePath + "\" />\n";
if (bundleContent.indexOf(referenceComment) === -1) {
Expand Down
14 changes: 13 additions & 1 deletion lib/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,19 @@ export interface Recipe {
repos?:pmb.RepositorySpec[];
path:string;
bundle?:string;
dependencies:{[path:string]:pmb.Dependency};
link?: { [name:string]: Link; };
dependencies:{ [path:string]:pmb.Dependency; };
}

export interface Link {
include?: boolean;
configPath?: string; // e.g. "./package.json",
}

export interface LinkResult {
managerName: string;
depName: string;
files: string[];
}

export interface GlobalConfig {
Expand Down
42 changes: 42 additions & 0 deletions test/cli_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,48 @@ describe("command line interface", ()=> {
});
});

describe("link sub-command", () => {

it("can link npm or bower definition files", ()=> {
var targetFile = path.resolve(testWorkingDir, "dtsm.json");

assert(!fs.existsSync(targetFile));
return Promise.resolve(null)
.then(()=> {
return new Promise((resolve, reject) => {
nexpect
.spawn("node", [dtsmPath, "--config", targetFile, "init"])
.run((err, stdout, exit) => {
assert(!err);
if (err) {
reject(err);
return;
}
assert(exit === 0);
assert(fs.existsSync(targetFile));
resolve();
});
});
})
.then(()=> {
return new Promise((resolve, reject) => {
nexpect
.spawn("node", [dtsmPath, "--config", targetFile, "link", "--save"])
.run((err, stdout, exit) => {
assert(!err);
if (err) {
reject(err);
return;
}
assert(exit === 0);
assert(fs.existsSync(targetFile));
resolve();
});
});
});
});
});

describe("refs sub-command", () => {

it("can show repository refs", done=> {
Expand Down
21 changes: 21 additions & 0 deletions test/fixture/dtsm-link.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"repos": [
{
"url": "https://github.com/borisyankov/DefinitelyTyped.git",
"ref": "master"
}
],
"path": "../../test-tmp/link",
"bundle": "../../test-tmp/link/bundle.d.ts",
"link": {
"npm": {
"include": true,
"configPath": "../../package.json"
},
"bower": {
"include": true,
"configPath": "../../bower.json"
}
},
"dependencies": {}
}
32 changes: 32 additions & 0 deletions test/index_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,38 @@ describe("Manager", ()=> {
});
});

describe("#link", ()=> {

var dtsmFilePath = "./test/fixture/dtsm-link.json";
var targetDir:string = JSON.parse(fs.readFileSync(dtsmFilePath, "utf8")).path;

beforeEach(()=> {
if (fs.existsSync(targetDir)) {
rimraf.sync(targetDir);
}
});

it("can found other package manager's dependencies", ()=> {
assert(!fs.existsSync(targetDir));

return dtsm
.createManager({configPath: dtsmFilePath})
.then(manager => {
return manager.link({}).then(result => {
assert(3 === result.length);
var dtsPath = "test-tmp/link/bundle.d.ts";
assert(fs.existsSync(dtsPath));

// check content
var dtsContent = fs.readFileSync(dtsPath, "utf8");
assert(dtsContent.indexOf(`/// <reference path="../../node_modules/commandpost/commandpost.d.ts" />`) !== -1);
assert(dtsContent.indexOf(`/// <reference path="../../node_modules/fs-git/fs-git.d.ts" />`) !== -1);
assert(dtsContent.indexOf(`/// <reference path="../../node_modules/packagemanager-backend/packagemanager-backend.d.ts" />`) !== -1);
});
});
});
});

describe("#fetch", ()=> {
it("can fetch from remote repos", ()=> {
return dtsm
Expand Down

0 comments on commit 4141749

Please sign in to comment.