Skip to content
This repository has been archived by the owner on Jan 5, 2024. It is now read-only.

Commit

Permalink
Implement reference and ambient module printing
Browse files Browse the repository at this point in the history
On installation, the CLI will now print removed references and possible ambient modules for the user to see. It uses the typings-specific URI schemes for copy and pasting.

Other fixes:

* Killed `ambient` in typings.json
* Improve parsing of dependency strings to not lower case (previously used `url.parse`, which lower cases the hostname)
  • Loading branch information
blakeembrey committed Dec 26, 2015
1 parent a88fbdf commit 7d1c813
Show file tree
Hide file tree
Showing 16 changed files with 470 additions and 202 deletions.
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ Supports configuration using [`rc`](https://github.com/dominictarr/rc). The conf
* **proxy** A HTTP(s) proxy URI for outgoing requests
### `main.d.ts` and `browser.d.ts`?
### `main.d.ts` And `browser.d.ts`
To simplify integration with TypeScript, two files - `typings/main.d.ts` and `typings/browser.d.ts` - are generated which reference all typings installed in the current project. To use this, you can add the reference to `tsconfig.json` files:
Expand All @@ -175,6 +175,10 @@ Or as a reference to the top of TypeScript files:
If you're building a front-end package it's recommended you use `typings/browser.d.ts` instead. The browser typings are compiled using the `browser` field overrides.
### References
During installation, any typings references (`/// <reference path="" />`) will be removed. This is because there's no simple way to include the contents from the other file within the project. With legacy projects, these references tend to denote both dependencies and ambient dependencies, and can't be relied on in any formal way.
### How Do I Use Typings With Git and Continuous Integration?
If you're already publishing your module with TypeScript, you're probably using NPM scripts to automate the build. To integrate **typings** into this flow, I recommend you run it as part of the `prepublish` or `build` steps. For example:
Expand Down
1 change: 1 addition & 0 deletions src/__test__/install-empty/typings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
Empty file.
Empty file.
8 changes: 4 additions & 4 deletions src/bin/typings-bundle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,12 @@ const { verbose } = args
const options = extend({ source: cwd }, args)

loader(bundle(options), { verbose })
.then(function (data) {
const file = options.browser ? data.browser : data.main
.then(function (output) {
const contents = options.browser ? output.browser : output.main

if (options.out) {
return loader(writeFile(resolve(cwd, options.out), file), options)
return loader(writeFile(resolve(cwd, options.out), contents), options)
}

process.stdout.write(file)
process.stdout.write(contents)
})
57 changes: 48 additions & 9 deletions src/bin/typings-install.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@

import minimist = require('minimist')
import extend = require('xtend')
import chalk = require('chalk')
import { install, installDependency } from '../typings'
import { loader, inquire } from '../utils/cli'
import { PROJECT_NAME } from '../utils/config'
import { VALID_SOURCES, isRegistryPath, parseRegistryPath, search, getVersions } from '../lib/registry'
import { ReferenceMap } from '../lib/compile'
import { DependencyTree } from '../interfaces/main'
import { archifyDependencyTree, handleError } from '../utils/cli'
import TypingsError from '../lib/error'

Expand Down Expand Up @@ -51,6 +54,46 @@ Options: [--name] [--save|--save-dev] [--ambient] [--production]
process.exit(0)
}

interface PrintOutput {
tree: DependencyTree
references?: ReferenceMap
missing?: ReferenceMap
}

/**
* Print the result to the user.
*/
function printResult (output: PrintOutput, options?: { name: string }) {
const references = Object.keys(output.references)
const missings = Object.keys(output.missing)

if (references.length) {
console.log(`References ${chalk.bold(`(not installed)`)}:`)

for (const reference of references) {
const info = output.references[reference]

console.log(` ${reference} ${chalk.gray(`(from ${info.map(x => x.name).join(', ')})`)}`)
}

console.log('')
}

if (missings.length) {
console.log(`Possible ambient modules ${chalk.bold(`(not installed)`)}:`)

for (const missing of missings) {
const info = output.missing[missing]

console.log(` ${missing} ${chalk.gray(`(from ${info.map(x => x.name).join(', ')})`)}`)
}

console.log('')
}

console.log(archifyDependencyTree(output.tree, options))
}

/**
* Install using CLI arguments.
*/
Expand All @@ -61,18 +104,14 @@ function installer (args: Args & minimist.ParsedArgs) {

if (!args._.length) {
return loader(install(options), args)
.then(function (tree) {
console.log(archifyDependencyTree(tree))
})
.then(output => printResult(output))
}

const dependency = args._[0]

if (!isRegistryPath(dependency)) {
return loader(installDependency(dependency, options), args)
.then(function (tree) {
console.log(archifyDependencyTree(tree, { name }))
})
.then(output => printResult(output, { name }))
}

const { name: dependencyName, version } = parseRegistryPath(dependency)
Expand Down Expand Up @@ -116,11 +155,11 @@ function installer (args: Args & minimist.ParsedArgs) {
console.log(`Writing dependency as "${saveName}"...`)
}

console.log('')

return loader(installation, args)
})
.then(function (tree) {
console.log(archifyDependencyTree(tree, { name: saveName }))
})
.then(output => printResult(output, { name: saveName }))
}

// User provided a source.
Expand Down
19 changes: 19 additions & 0 deletions src/install.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,4 +87,23 @@ test('install', t => {
})
})
})

t.test('install empty', t => {
const FIXTURE_DIR = join(__dirname, '__test__/install-empty')

return install({
cwd: FIXTURE_DIR,
production: false
})
.then(function () {
return Promise.all([
readFile(join(FIXTURE_DIR, 'typings/main.d.ts'), 'utf8'),
readFile(join(FIXTURE_DIR, 'typings/browser.d.ts'), 'utf8')
])
})
.then(function ([main, browser]) {
t.equal(main, '')
t.equal(browser, '')
})
})
})
63 changes: 31 additions & 32 deletions src/install.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import extend = require('xtend')
import Promise = require('native-or-bluebird')
import { dirname } from 'path'
import { resolveDependency, resolveTypeDependencies } from './lib/dependencies'
import compile, { Options as CompileOptions } from './lib/compile'
import compile, { Options as CompileOptions, CompiledOutput } from './lib/compile'
import { findProject } from './utils/find'
import { writeDependency, transformConfig, mkdirp, getTypingsLocation, touch } from './utils/fs'
import { parseDependency } from './utils/parse'
Expand Down Expand Up @@ -31,15 +31,17 @@ export interface InstallOptions {
/**
* Install all dependencies on the current project.
*/
export function install (options: InstallOptions): Promise<DependencyTree> {
export function install (options: InstallOptions): Promise<{ tree: DependencyTree }> {
return resolveTypeDependencies({ cwd: options.cwd, dev: !options.production, ambient: true })
.then(tree => {
const cwd = dirname(tree.src)
const queue: [string, DependencyTree, boolean][] = []
const queue: Array<Promise<any>> = []

function addToQueue (deps: DependencyBranch, ambient: boolean) {
for (const key of Object.keys(deps)) {
queue.push([key, deps[key], ambient])
for (const name of Object.keys(deps)) {
const tree = deps[name]

queue.push(installDependencyTree(tree, { cwd, name, ambient, meta: true }))
}
}

Expand All @@ -48,33 +50,28 @@ export function install (options: InstallOptions): Promise<DependencyTree> {
addToQueue(tree.ambientDependencies, true)
addToQueue(tree.ambientDevDependencies, true)

// Create the `.d.ts` files, even when nothing gets installed.
if (queue.length === 0) {
const { typingsDir, mainDtsFile, browserDtsFile } = getTypingsLocation({ cwd })

return mkdirp(typingsDir)
.then(() => {
return Promise.all([
touch(mainDtsFile, {}),
touch(browserDtsFile, {})
])
})
.then(() => tree)
}

// Install each dependency after each other.
function chain (result: Promise<DependencyTree>, [name, tree, ambient]) {
return result.then(() => installDependencyTree(tree, { cwd, name, ambient, meta: true }))
}

return queue.reduce(chain, Promise.resolve()).then(() => tree)
return Promise.all(queue)
.then(installed => {
if (installed.length === 0) {
const { typingsDir, mainDtsFile, browserDtsFile } = getTypingsLocation({ cwd })

return mkdirp(typingsDir)
.then(() => {
return Promise.all([
touch(mainDtsFile, {}),
touch(browserDtsFile, {})
])
})
}
})
.then(() => ({ tree }))
})
}

/**
* Install a dependency into the currect project.
*/
export function installDependency (dependency: string, options: InstallDependencyOptions): Promise<DependencyTree> {
export function installDependency (dependency: string, options: InstallDependencyOptions): Promise<CompiledOutput> {
if (!options.name) {
return Promise.reject(new TypeError('You must specify a name for the dependency'))
}
Expand All @@ -89,7 +86,7 @@ export function installDependency (dependency: string, options: InstallDependenc
/**
* Install from a dependency string.
*/
function installTo (location: string, options: InstallDependencyOptions): Promise<DependencyTree> {
function installTo (location: string, options: InstallDependencyOptions): Promise<CompiledOutput> {
const dependency = parseDependency(location)

return resolveDependency(dependency, options)
Expand All @@ -104,17 +101,17 @@ function installTo (location: string, options: InstallDependencyOptions): Promis
ambient: options.ambient,
meta: true
})
.then(() => writeToConfig(dependency, options))
.then(() => tree)
.then(result => {
return writeToConfig(dependency, options).then(() => result)
})
})
}

/**
* Compile a dependency tree into the users typings.
*/
function installDependencyTree (tree: DependencyTree, options: CompileOptions) {
return compile(tree, options)
.then(definitions => writeDependency(definitions, options))
function installDependencyTree (tree: DependencyTree, options: CompileOptions): Promise<CompiledOutput> {
return compile(tree, options).then(result => writeDependency(result, options))
}

/**
Expand Down Expand Up @@ -143,4 +140,6 @@ function writeToConfig (dependency: Dependency, options: InstallDependencyOption
return config
})
}

return Promise.resolve()
}
5 changes: 2 additions & 3 deletions src/interfaces/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ export interface ConfigJson {
// Typing information.
main?: string
browser?: Browser
ambient?: boolean
typings?: string
browserTypings?: string | Browser

Expand Down Expand Up @@ -55,6 +54,7 @@ export interface Dependency {
type: string
raw: string
location: string
meta?: any
}

/**
Expand All @@ -68,10 +68,9 @@ export interface DependencyTree {
typings?: string
browserTypings?: Browser
parent?: DependencyTree
type: string
src: string
raw: string
missing: boolean
ambient: boolean
dependencies: DependencyBranch
devDependencies: DependencyBranch
ambientDependencies: DependencyBranch
Expand Down

0 comments on commit 7d1c813

Please sign in to comment.