Skip to content

Commit

Permalink
Merge pull request #13 from jeffijoe/feat-version-range
Browse files Browse the repository at this point in the history
Use semantic version range prefix for typings package
  • Loading branch information
jeffijoe authored Oct 7, 2018
2 parents a7ef30b + 35f1437 commit bef3793
Show file tree
Hide file tree
Showing 7 changed files with 319 additions and 374 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ If `--dry` is specified, will not actually write to the file, it only prints add

**Note**: `typesync` only modifies your `package.json` - you still need to run `npm install`, or — if drinking the k00laid — `yarn`.

## Typings package version

TypeSync will add the latest available typings package that are missing — this means TypeSync won't touch existing typings packages that are present in `package.json`.

If you use a Semver `^` or `~` for a package, the same prefix will be used for the typings package. If you pin to an exact version (`"some-package": "1.2.3"`), no prefix will be written.

# Why?

Installing typings manually sucks. Flow has `flow-typed` which installs type definitions by looking at a `package.json`, which would be cool to have for TypeScript. Now we do!
Expand Down
46 changes: 26 additions & 20 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,19 @@
"coveralls": "jest --coverage && cat ./coverage/lcov.info | coveralls",
"build": "rimraf lib && tsc -p tsconfig.build.json --sourceMap --declaration",
"run-cli": "npm run build && node bin/typesync",
"precommit": "lint-staged",
"do:publish": "npm run lint && npm run cover && npm run build && npm publish",
"release:patch": "npm version patch && npm run do:publish && git push --follow-tags",
"release:minor": "npm version minor && npm run do:publish && git push --follow-tags",
"release:prerelease": "npm version prerelease && npm run do:publish && git push --follow-tags"
},
"lint-staged": {
"*.ts": [
"tslint --project tsconfig.json --fix",
"prettier --write",
"git add"
]
},
"repository": {
"type": "git",
"url": "git+https://github.com/jeffijoe/typesync.git"
Expand All @@ -38,23 +46,30 @@
"url": "https://github.com/jeffijoe/typesync/issues"
},
"homepage": "https://github.com/jeffijoe/typesync#readme",
"dependencies": {
"awilix": "^3.0.9",
"axios": "^0.18.0",
"chalk": "^2.4.1",
"detect-indent": "^5.0.0",
"ora": "^3.0.0",
"tslib": "^1.9.3"
},
"devDependencies": {
"@types/detect-indent": "^5.0.0",
"@types/jest": "^23.1.6",
"@types/lodash": "^4.14.112",
"@types/jest": "^23.3.2",
"@types/ora": "^1.3.4",
"@types/prettier": "^1.13.1",
"@types/rimraf": "^2.0.2",
"coveralls": "^3.0.2",
"jest": "^23.4.1",
"nodemon": "^1.18.2",
"prettier": "^1.13.7",
"jest": "^23.6.0",
"nodemon": "^1.18.4",
"prettier": "^1.14.3",
"rimraf": "^2.6.2",
"ts-jest": "^23.0.0",
"tslint": "^5.10.0",
"tslint-config-prettier": "^1.13.0",
"tslint-config-standard": "^7.1.0",
"typescript": "^2.9.2"
"ts-jest": "^23.10.1",
"tslint": "^5.11.0",
"tslint-config-prettier": "^1.15.0",
"tslint-config-standard": "^8.0.1",
"typescript": "^3.0.3"
},
"jest": {
"testEnvironment": "node",
Expand All @@ -69,7 +84,7 @@
"/node_modules/"
],
"transform": {
".(ts|tsx)": "<rootDir>/node_modules/ts-jest/preprocessor.js"
".(ts|tsx)": "ts-jest"
},
"testRegex": "(/__tests__/.*\\.(test|spec))\\.(ts|tsx|js)$",
"testPathIgnorePatterns": [
Expand All @@ -80,14 +95,5 @@
"tsx",
"js"
]
},
"dependencies": {
"awilix": "^3.0.8",
"axios": "^0.18.0",
"chalk": "^2.4.1",
"detect-indent": "^5.0.0",
"lodash": "4.17.10",
"ora": "^2.1.0",
"tslib": "^1.9.3"
}
}
16 changes: 14 additions & 2 deletions src/__tests__/type-syncer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ const typedefs: ITypeDefinition[] = [
// None for package6
{
typingsName: 'myorg__package7'
},
{
typingsName: 'package8'
},
{
typingsName: 'package9'
}
]

Expand All @@ -44,7 +50,9 @@ function buildSyncer() {
package6: '^1.0.0'
},
peerDependencies: {
'@myorg/package7': '^1.0.0'
'@myorg/package7': '^1.0.0',
package8: '~1.0.0',
package9: '1.0.0'
}
}

Expand Down Expand Up @@ -77,14 +85,18 @@ describe('type syncer', () => {
'@types/package4': '^1.0.0',
'@types/package5': '^1.0.0',
'@types/myorg__package7': '^1.0.0',
'@types/package8': '~1.0.0',
'@types/package9': '1.0.0',
package4: '^1.0.0',
package5: '^1.0.0'
})
expect(result.newTypings.map(x => x.typingsName).sort()).toEqual([
'myorg__package7',
'package1',
'package3',
'package5'
'package5',
'package8',
'package9'
])
})

Expand Down
2 changes: 2 additions & 0 deletions src/type-definition-source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export function createTypeDefinitionSource(): ITypeDefinitionSource {
}))
)
},

/**
* Gets the latest version of a typings package.
*/
Expand All @@ -43,6 +44,7 @@ export function createTypeDefinitionSource(): ITypeDefinitionSource {

/**
* Unzips a gzip-encoded response.
*
* @param response
*/
function unzipResponse(response: AxiosResponse) {
Expand Down
89 changes: 69 additions & 20 deletions src/type-syncer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import {
ITypeDefinitionSource,
ITypeDefinition,
IPackageFile,
ISyncOptions
ISyncOptions,
IDependenciesSection,
IPackageVersion
} from './types'
import { uniq, filterMap, mergeObjects, typed, orderObject } from './util'
import { filterMap, mergeObjects, typed, orderObject, uniq } from './util'

/**
* Creates a type syncer.
Expand All @@ -28,28 +30,29 @@ export function createTypeSyncer(
typeDefinitionSource.fetch()
])

const allPackageNames = uniq([
...((file.dependencies &&
Object.keys(file.dependencies)) /* istanbul ignore next*/ ||
[]),
...((file.devDependencies &&
Object.keys(file.devDependencies)) /* istanbul ignore next*/ ||
[]),
...((file.optionalDependencies &&
Object.keys(file.optionalDependencies)) /* istanbul ignore next*/ ||
[]),
...((file.peerDependencies &&
Object.keys(file.peerDependencies)) /* istanbul ignore next*/ ||
[])
])
const allPackages = [
...getPackagesFromSection(file.dependencies),
...getPackagesFromSection(file.devDependencies),
...getPackagesFromSection(file.optionalDependencies),
...getPackagesFromSection(file.peerDependencies)
]
const allPackageNames = uniq(allPackages.map(p => p.name))

const newTypings = filterNewTypings(allPackageNames, allTypings)
const devDepsToAdd = await Promise.all(
newTypings.map(async t => {
const latestVersion = await typeDefinitionSource.getLatestTypingsVersion(
t.typingsName
)
return { [typed(t.typingsName)]: `^${latestVersion}` }
const codePackage = allPackages.find(
p => p.name === t.codePackageName
)
const semverRangeSpecifier = codePackage
? getSemverRangeSpecifier(codePackage.version)
: '^'
return {
[typed(t.typingsName)]: semverRangeSpecifier + latestVersion
}
})
).then(mergeObjects)

Expand All @@ -71,15 +74,15 @@ export function createTypeSyncer(
}

/**
* Returns an array of new typings.
* Returns an array of new typings as well as the code package name that was matched to it.
*
* @param allPackageNames Used to filter the typings that are new.
* @param allTypings All typings available
*/
function filterNewTypings(
allPackageNames: Array<string>,
allTypings: Array<ITypeDefinition>
): Array<ITypeDefinition> {
): Array<ITypeDefinition & { codePackageName: string }> {
const existingTypings = allPackageNames.filter(x => x.startsWith('@types/'))
return filterMap(allPackageNames, p => {
const scopeInfo = getPackageScope(p)
Expand All @@ -99,7 +102,10 @@ function filterNewTypings(
return false
}

return typingsForPackage
return {
...typingsForPackage,
codePackageName: p
}
})
}

Expand All @@ -117,3 +123,46 @@ function getPackageScope(packageName: string): [string, string] | null {

return [matches[1], matches[2]]
}

/**
* Gets packages from a dependencies section.
*
* @param section
*/
function getPackagesFromSection(
section?: IDependenciesSection
): Array<IPackageVersion> {
/* istanbul ignore next */
if (!section) {
return []
}

const result: Array<IPackageVersion> = []
for (const name in section) {
result.push({
name,
version: section[name]
})
}

return result
}

const CARET = '^'.charCodeAt(0)
const TILDE = '~'.charCodeAt(0)

/**
* Gets the semver range specifier (~, ^)
* @param version
*/
function getSemverRangeSpecifier(version: string): string {
if (version.charCodeAt(0) === CARET) {
return '^'
}

if (version.charCodeAt(0) === TILDE) {
return '~'
}

return ''
}
8 changes: 8 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,14 @@ export interface IDependenciesSection {
[packageName: string]: string
}

/**
* Package + version.
*/
export interface IPackageVersion {
name: string
version: string
}

/**
* Represents a type definition pulled from a source.
*/
Expand Down
Loading

0 comments on commit bef3793

Please sign in to comment.