mirror of
https://github.com/chenasraf/DefinitelyTyped-tools.git
synced 2026-05-18 01:49:03 +00:00
Publish work
This commit is contained in:
committed by
Andrew Branch
parent
67f795f03d
commit
c3f9e176a7
@@ -18,7 +18,9 @@ export enum DefinitionFileKind {
|
||||
// More than one 'declare module "foo"''
|
||||
MultipleModules,
|
||||
// Augments an external module
|
||||
ModuleAugmentation
|
||||
ModuleAugmentation,
|
||||
// Old-style UMD
|
||||
OldUMD
|
||||
}
|
||||
|
||||
export enum RejectionReason {
|
||||
@@ -46,7 +48,7 @@ export function isFail(t: TypingParseSucceedResult | TypingParseFailResult): t i
|
||||
}
|
||||
|
||||
export interface TypingsData {
|
||||
type: string;
|
||||
kind: string;
|
||||
|
||||
moduleDependencies: string[];
|
||||
libraryDependencies: string[];
|
||||
@@ -54,26 +56,22 @@ export interface TypingsData {
|
||||
// e.g. https://github.com/DefinitelyTyped
|
||||
sourceRepoURL: string;
|
||||
|
||||
// The name of the primary definition file
|
||||
// The name of the primary definition file, e.g. 'jquery.d.ts'
|
||||
definitionFilename: string;
|
||||
|
||||
// The name of the library (human readable, e.g. might be 'Moment.js' even though packageName is 'moment')
|
||||
libraryName: string;
|
||||
|
||||
// True if the 'packageName' corresponds to the NPM package of the same name
|
||||
hasNpmPackage: boolean;
|
||||
|
||||
// The NPM name to publish this under
|
||||
// The NPM name to publish this under, e.g. 'jquery'. May not be lower-cased yet.
|
||||
packageName: string;
|
||||
|
||||
// Parsed from 'Definitions by:'
|
||||
authors: string;
|
||||
// Parent folder name in the source repo
|
||||
folder: string;
|
||||
|
||||
// Optionally-presesnt name or URL of the project
|
||||
// Optionally-present name or URL of the project, e.g. 'http://cordova.apache.org'
|
||||
projectName: string;
|
||||
|
||||
// Names introduced into the global scope
|
||||
// Names introduced into the global scope by this definition set
|
||||
globals: string[];
|
||||
|
||||
// The major version of the library (e.g. '1' for 1.0, '2' for 2.0)
|
||||
@@ -81,21 +79,26 @@ export interface TypingsData {
|
||||
// The minor version of the library
|
||||
libraryMinorVersion: string;
|
||||
|
||||
// Files that should be published with this definition
|
||||
// The full path to the containing folder of all files, e.g. 'C:/github/DefinitelyTyped'
|
||||
root: string;
|
||||
|
||||
// Files that should be published with this definition, e.g. ['jquery.d.ts', 'jquery-extras.d.ts']
|
||||
files: string[];
|
||||
}
|
||||
|
||||
const augmentedGlobals = ['Array',' Function', 'String', 'Number', 'Window', 'Date', 'StringConstructor', 'NumberConstructor', 'Math', 'HTMLElement'];
|
||||
|
||||
function isSupportedFileKind(kind: DefinitionFileKind) {
|
||||
switch(kind) {
|
||||
case DefinitionFileKind.Unknown:
|
||||
case DefinitionFileKind.MultipleModules:
|
||||
case DefinitionFileKind.Mixed:
|
||||
case DefinitionFileKind.DeclareModule:
|
||||
return false;
|
||||
case DefinitionFileKind.Global:
|
||||
case DefinitionFileKind.ProperModule:
|
||||
case DefinitionFileKind.ModuleAugmentation:
|
||||
case DefinitionFileKind.UMD:
|
||||
case DefinitionFileKind.OldUMD:
|
||||
return true;
|
||||
default:
|
||||
throw new Error('Should not be here');
|
||||
@@ -111,6 +114,7 @@ enum DeclarationFlags {
|
||||
Value = 1 << 0,
|
||||
Type = 1 << 1,
|
||||
Namespace = 1 << 2,
|
||||
Augmentation = 1 << 3
|
||||
}
|
||||
|
||||
function getNamespaceFlags(ns: ts.ModuleDeclaration): DeclarationFlags {
|
||||
@@ -161,20 +165,29 @@ export function getTypingInfo(directory: string): TypingParseFailResult | Typing
|
||||
log.push(`Found ${files.length} files`);
|
||||
|
||||
const declFiles = files.filter(f => /\.d\.ts$/.test(f));
|
||||
const candidates = [path.basename(directory) + ".d.ts", "index.d.ts"];
|
||||
log.push(`Found ${declFiles.length} .d.ts files (${declFiles.join(', ')})`);
|
||||
|
||||
if (declFiles.length !== 1) {
|
||||
log.push('Exiting, can only process directories with exactly 1 .d.ts file');
|
||||
return { log, rejectionReason: RejectionReason.TooManyFiles };
|
||||
let entryPointFilename: string;
|
||||
if (declFiles.length === 1) {
|
||||
entryPointFilename = declFiles[0];
|
||||
}
|
||||
else if(declFiles.length > 1) {
|
||||
// You can have [foldername].d.ts, or index.d.ts to rescue yourself from this situation
|
||||
for(const candidate of candidates) {
|
||||
if(declFiles.indexOf(candidate) >= 0) {
|
||||
log.push(`Used ${candidate} as entry point`);
|
||||
entryPointFilename = candidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const declFilename = declFiles[0];
|
||||
log.push(`Parse ${declFilename}`);
|
||||
const fullPath = path.join(directory, declFilename);
|
||||
|
||||
let content = fs.readFileSync(fullPath, 'utf-8');
|
||||
if (content.charCodeAt(0) === 0xFEFF) content = content.substr(1);
|
||||
const src = ts.createSourceFile('test.d.ts', content, ts.ScriptTarget.Latest, true);
|
||||
if (entryPointFilename === undefined) {
|
||||
log.push('Exiting, found either zero or more than one .d.ts file and none of ' + candidates.join(' or '));
|
||||
return { log, rejectionReason: RejectionReason.TooManyFiles };
|
||||
}
|
||||
const entryPointContent = readFile(entryPointFilename);
|
||||
|
||||
let hasUmdDecl = false;
|
||||
let isProperModule = false;
|
||||
@@ -182,101 +195,134 @@ export function getTypingInfo(directory: string): TypingParseFailResult | Typing
|
||||
let ambientModuleCount = 0;
|
||||
|
||||
const moduleDependencies: string[] = [];
|
||||
const referencedLibraries: string[] = [];
|
||||
|
||||
let globalSymbols: { [name: string]: ts.SymbolFlags } = {};
|
||||
function recordSymbol(name: string, flags: DeclarationFlags) {
|
||||
globalSymbols[name] = (globalSymbols[name] || DeclarationFlags.None) | flags;
|
||||
}
|
||||
|
||||
src.getChildren()[0].getChildren().forEach(node => {
|
||||
switch(node.kind) {
|
||||
case ts.SyntaxKind.GlobalModuleExportDeclaration:
|
||||
const globalName = (node as ts.GlobalModuleExportDeclaration).name.getText();
|
||||
log.push(`Found UMD module declaration for global ${globalName}`);
|
||||
// Don't set hasGlobalDeclarations = true even though we add a symbol here
|
||||
// since this is still a legal module-only declaration
|
||||
globalSymbols[globalName] = ts.SymbolFlags.Value;
|
||||
isProperModule = true;
|
||||
hasUmdDecl = true;
|
||||
break;
|
||||
const processQueue = [entryPointFilename];
|
||||
const completeList: string[] = [];
|
||||
|
||||
case ts.SyntaxKind.ModuleDeclaration:
|
||||
if (node.flags & ts.NodeFlags.Export) {
|
||||
log.push(`Found exported namespace "${(node as ts.ModuleDeclaration).name.getText()}"`);
|
||||
isProperModule = true;
|
||||
} else {
|
||||
const nameKind = (node as ts.ModuleDeclaration).name.kind;
|
||||
if (nameKind === ts.SyntaxKind.StringLiteral) {
|
||||
log.push(`Found ambient external module ${(node as ts.ModuleDeclaration).name.getText()}`);
|
||||
ambientModuleCount++;
|
||||
} else {
|
||||
const moduleName = (node as ts.ModuleDeclaration).name.getText();
|
||||
log.push(`Found global namespace declaration "${moduleName}"`);
|
||||
hasGlobalDeclarations = true;
|
||||
//console.log(node.getText());
|
||||
recordSymbol(moduleName, getNamespaceFlags(node as ts.ModuleDeclaration));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ts.SyntaxKind.VariableStatement:
|
||||
if (node.flags & ts.NodeFlags.Export) {
|
||||
log.push('Found exported variables');
|
||||
isProperModule = true;
|
||||
} else {
|
||||
(node as ts.VariableStatement).declarationList.declarations.forEach(decl => {
|
||||
const declName = decl.name.getText();
|
||||
log.push(`Found global variable ${declName}`);
|
||||
recordSymbol(declName, DeclarationFlags.Value);
|
||||
});
|
||||
hasGlobalDeclarations = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case ts.SyntaxKind.InterfaceDeclaration:
|
||||
case ts.SyntaxKind.TypeAliasDeclaration:
|
||||
case ts.SyntaxKind.EnumDeclaration:
|
||||
case ts.SyntaxKind.ClassDeclaration:
|
||||
case ts.SyntaxKind.FunctionDeclaration:
|
||||
// If these nodes have an 'export' modifier, the file is an external module
|
||||
if (node.flags & ts.NodeFlags.Export) {
|
||||
log.push(`Found exported declaration "${(node as ts.Declaration).name.getText()}"`);
|
||||
isProperModule = true;
|
||||
} else {
|
||||
const declName = (node as ts.Declaration).name.getText();
|
||||
const isType = node.kind === ts.SyntaxKind.InterfaceDeclaration || node.kind === ts.SyntaxKind.TypeAliasDeclaration;
|
||||
log.push(`Found global ${isType ? 'type' : 'value'} declaration "${declName}"`);
|
||||
recordSymbol(declName, isType ? DeclarationFlags.Type : DeclarationFlags.Value);
|
||||
hasGlobalDeclarations = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case ts.SyntaxKind.ImportEqualsDeclaration:
|
||||
if((node as ts.ImportEqualsDeclaration).moduleReference.kind === ts.SyntaxKind.ExternalModuleReference) {
|
||||
const ref = (node as ts.ImportEqualsDeclaration).moduleReference.getText();
|
||||
moduleDependencies.push(stripQuotes(ref));
|
||||
log.push(`Found import = declaration from ${ref}`);
|
||||
isProperModule = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case ts.SyntaxKind.ImportDeclaration:
|
||||
if((node as ts.ImportDeclaration).moduleSpecifier.kind === ts.SyntaxKind.StringLiteral) {
|
||||
const ref = (node as ts.ImportDeclaration).moduleSpecifier.getText();
|
||||
moduleDependencies.push(stripQuotes(ref));
|
||||
log.push(`Found import declaration from ${ref}`);
|
||||
isProperModule = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case ts.SyntaxKind.ExportDeclaration:
|
||||
case ts.SyntaxKind.ExportAssignment:
|
||||
// These nodes always indicate an external module
|
||||
log.push(`Found export assignment or export declaration`);
|
||||
isProperModule = true;
|
||||
break;
|
||||
while(processQueue.length > 0) {
|
||||
const filename = processQueue.pop();
|
||||
if (completeList.indexOf(filename) >= 0) {
|
||||
continue;
|
||||
}
|
||||
});
|
||||
completeList.push(filename);
|
||||
|
||||
log.push(`Parse ${filename}`);
|
||||
let content = readFile(filename);
|
||||
|
||||
const src = ts.createSourceFile('test.d.ts', content, ts.ScriptTarget.Latest, true);
|
||||
src.referencedFiles.forEach(ref => {
|
||||
// Add referenced files to processing queue
|
||||
if(ref.fileName.charAt(0) !== '.') {
|
||||
processQueue.push(path.join(path.dirname(filename), ref.fileName));
|
||||
}
|
||||
});
|
||||
|
||||
// TODO: Remove type assertion
|
||||
((<any>src).referencedLibraries || []).forEach((ref: {fileName: string}) => {
|
||||
if(referencedLibraries.indexOf(ref.fileName) < 0) {
|
||||
referencedLibraries.push(ref.fileName);
|
||||
}
|
||||
});
|
||||
|
||||
src.getChildren()[0].getChildren().forEach(node => {
|
||||
switch(node.kind) {
|
||||
case ts.SyntaxKind.GlobalModuleExportDeclaration:
|
||||
const globalName = (node as ts.GlobalModuleExportDeclaration).name.getText();
|
||||
log.push(`Found UMD module declaration for global ${globalName}`);
|
||||
// Don't set hasGlobalDeclarations = true even though we add a symbol here
|
||||
// since this is still a legal module-only declaration
|
||||
globalSymbols[globalName] = ts.SymbolFlags.Value;
|
||||
isProperModule = true;
|
||||
hasUmdDecl = true;
|
||||
break;
|
||||
|
||||
case ts.SyntaxKind.ModuleDeclaration:
|
||||
if (node.flags & ts.NodeFlags.Export) {
|
||||
log.push(`Found exported namespace "${(node as ts.ModuleDeclaration).name.getText()}"`);
|
||||
isProperModule = true;
|
||||
} else {
|
||||
const nameKind = (node as ts.ModuleDeclaration).name.kind;
|
||||
if (nameKind === ts.SyntaxKind.StringLiteral) {
|
||||
log.push(`Found ambient external module ${(node as ts.ModuleDeclaration).name.getText()}`);
|
||||
ambientModuleCount++;
|
||||
} else {
|
||||
const moduleName = (node as ts.ModuleDeclaration).name.getText();
|
||||
log.push(`Found global namespace declaration "${moduleName}"`);
|
||||
hasGlobalDeclarations = true;
|
||||
recordSymbol(moduleName, getNamespaceFlags(node as ts.ModuleDeclaration));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ts.SyntaxKind.VariableStatement:
|
||||
if (node.flags & ts.NodeFlags.Export) {
|
||||
log.push('Found exported variables');
|
||||
isProperModule = true;
|
||||
} else {
|
||||
(node as ts.VariableStatement).declarationList.declarations.forEach(decl => {
|
||||
const declName = decl.name.getText();
|
||||
log.push(`Found global variable ${declName}`);
|
||||
recordSymbol(declName, DeclarationFlags.Value);
|
||||
});
|
||||
hasGlobalDeclarations = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case ts.SyntaxKind.InterfaceDeclaration:
|
||||
case ts.SyntaxKind.TypeAliasDeclaration:
|
||||
case ts.SyntaxKind.EnumDeclaration:
|
||||
case ts.SyntaxKind.ClassDeclaration:
|
||||
case ts.SyntaxKind.FunctionDeclaration:
|
||||
// If these nodes have an 'export' modifier, the file is an external module
|
||||
if (node.flags & ts.NodeFlags.Export) {
|
||||
log.push(`Found exported declaration "${(node as ts.Declaration).name.getText()}"`);
|
||||
isProperModule = true;
|
||||
} else {
|
||||
const declName = (node as ts.Declaration).name.getText();
|
||||
const isType = node.kind === ts.SyntaxKind.InterfaceDeclaration || node.kind === ts.SyntaxKind.TypeAliasDeclaration;
|
||||
log.push(`Found global ${isType ? 'type' : 'value'} declaration "${declName}"`);
|
||||
recordSymbol(declName, isType ? DeclarationFlags.Type : DeclarationFlags.Value);
|
||||
hasGlobalDeclarations = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case ts.SyntaxKind.ImportEqualsDeclaration:
|
||||
if((node as ts.ImportEqualsDeclaration).moduleReference.kind === ts.SyntaxKind.ExternalModuleReference) {
|
||||
const ref = (node as ts.ImportEqualsDeclaration).moduleReference.getText();
|
||||
moduleDependencies.push(stripQuotes(ref));
|
||||
log.push(`Found import = declaration from ${ref}`);
|
||||
isProperModule = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case ts.SyntaxKind.ImportDeclaration:
|
||||
if((node as ts.ImportDeclaration).moduleSpecifier.kind === ts.SyntaxKind.StringLiteral) {
|
||||
const ref = (node as ts.ImportDeclaration).moduleSpecifier.getText();
|
||||
moduleDependencies.push(stripQuotes(ref));
|
||||
log.push(`Found import declaration from ${ref}`);
|
||||
isProperModule = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case ts.SyntaxKind.ExportDeclaration:
|
||||
case ts.SyntaxKind.ExportAssignment:
|
||||
// These nodes always indicate an external module
|
||||
log.push(`Found export assignment or export declaration`);
|
||||
isProperModule = true;
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let hasGlobalAugmentations = false;
|
||||
const globals = Object.keys(globalSymbols).filter(s => augmentedGlobals.indexOf(s) < 0);
|
||||
const globalAugments = Object.keys(globalSymbols).filter(s => augmentedGlobals.indexOf(s) >= 0);
|
||||
|
||||
let fileKind = DefinitionFileKind.Unknown;
|
||||
if (isProperModule) {
|
||||
@@ -295,8 +341,13 @@ export function getTypingInfo(directory: string): TypingParseFailResult | Typing
|
||||
} else {
|
||||
if (hasGlobalDeclarations) {
|
||||
if (ambientModuleCount == 1) {
|
||||
log.push(`Global declarations and one ambient module declaration, this is a Mixed file`);
|
||||
fileKind = DefinitionFileKind.Mixed;
|
||||
if (globals.length === 1) {
|
||||
log.push(`One global declaration and one ambient module declaration, this is an OldUMD file`);
|
||||
fileKind = DefinitionFileKind.OldUMD;
|
||||
} else {
|
||||
log.push(`${globals.length} global declarations and one ambient module declaration, this is a Mixed file`);
|
||||
fileKind = DefinitionFileKind.Mixed;
|
||||
}
|
||||
} else if(ambientModuleCount > 1) {
|
||||
log.push(`Global declarations and multiple ambient module declaration, this is a MultipleModules file`);
|
||||
fileKind = DefinitionFileKind.MultipleModules;
|
||||
@@ -320,13 +371,8 @@ export function getTypingInfo(directory: string): TypingParseFailResult | Typing
|
||||
return { log, rejectionReason: RejectionReason.BadFileFormat };
|
||||
}
|
||||
|
||||
if (src.referencedFiles.length > 0) {
|
||||
log.push(`Exiting, typings files cannot have "/// <reference path=...>" directives`);
|
||||
return { log, rejectionReason: RejectionReason.ReferencePaths };
|
||||
}
|
||||
|
||||
function regexMatch(rx: RegExp, defaultValue: string): string {
|
||||
const match = rx.exec(content);
|
||||
const match = rx.exec(entryPointContent);
|
||||
return match ? match[1] : defaultValue;
|
||||
}
|
||||
|
||||
@@ -335,27 +381,36 @@ export function getTypingInfo(directory: string): TypingParseFailResult | Typing
|
||||
const libraryMinorVersion = regexMatch(/^\/\/ Type definitions for \D+ v?\d+\.(\d+)/m, '0');
|
||||
const libraryName = regexMatch(/^\/\/ Type definitions for ([A-Za-z]+)/m, 'Unknown').trim();
|
||||
const projectName = regexMatch(/^\/\/ Project: (.+)$/m, '');
|
||||
const packageName = isProperModule ? path.basename(directory) : undefined;
|
||||
const packageName = path.basename(directory);
|
||||
const sourceRepoURL = 'https://www.github.com/DefinitelyTyped/DefinitelyTyped';
|
||||
|
||||
if(packageName !== packageName.toLowerCase()) {
|
||||
log.push(`!!! WARNING: ${packageName} !== ${packageName.toLowerCase()}`);
|
||||
}
|
||||
|
||||
return {
|
||||
log,
|
||||
data: {
|
||||
authors,
|
||||
definitionFilename: declFilename,
|
||||
libraryDependencies: src['referencedLibraries'], // TODO update
|
||||
definitionFilename: entryPointFilename,
|
||||
libraryDependencies: referencedLibraries,
|
||||
moduleDependencies,
|
||||
folder: path.basename(directory),
|
||||
hasNpmPackage: false,
|
||||
libraryMajorVersion,
|
||||
libraryMinorVersion,
|
||||
libraryName,
|
||||
packageName,
|
||||
projectName,
|
||||
sourceRepoURL,
|
||||
type: DefinitionFileKind[fileKind],
|
||||
kind: DefinitionFileKind[fileKind],
|
||||
globals: Object.keys(globalSymbols).filter(k => !!(globalSymbols[k] & DeclarationFlags.Value)),
|
||||
files: [declFiles[0]]
|
||||
root: path.resolve(directory),
|
||||
files: declFiles
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function readFile(fileName: string) {
|
||||
const result = fs.readFileSync(path.join(directory, fileName), 'utf-8');
|
||||
// Skip BOM
|
||||
return (result.charCodeAt(0) === 0xFEFF) ? result.substr(1) : result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import { TypingsData, DefinitionFileKind } from './definition-parser';
|
||||
import * as fs from 'fs';
|
||||
import * as crypto from 'crypto';
|
||||
import * as path from 'path';
|
||||
import * as child_process from 'child_process';
|
||||
|
||||
export interface PublishSettings {
|
||||
// e.g. 'typings', not '@typings'
|
||||
@@ -20,7 +21,7 @@ namespace Versions {
|
||||
};
|
||||
}
|
||||
|
||||
export function performUpdate(key: string, content: string, update: (version: number) => void) {
|
||||
export function performUpdate(key: string, content: string, update: (version: number) => boolean) {
|
||||
let data: VersionMap = fs.existsSync(versionFilename) ? JSON.parse(fs.readFileSync(versionFilename, 'utf-8')) : {};
|
||||
|
||||
const hashValue = computeHash(key);
|
||||
@@ -30,12 +31,13 @@ namespace Versions {
|
||||
data[key] = entry = { lastVersion: 0, lastContentHash: '' };
|
||||
}
|
||||
|
||||
if (entry.lastContentHash !== hashValue) {
|
||||
if (entry.lastContentHash !== hashValue || process.argv.some(arg => arg === '--forceUpdate')) {
|
||||
const vNext = entry.lastVersion + 1;
|
||||
update(vNext);
|
||||
|
||||
data[key] = { lastVersion: vNext, lastContentHash: hashValue };
|
||||
fs.writeFileSync(versionFilename, JSON.stringify(data, undefined, 4));
|
||||
|
||||
if(update(vNext)) {
|
||||
data[key] = { lastVersion: vNext, lastContentHash: hashValue };
|
||||
fs.writeFileSync(versionFilename, JSON.stringify(data, undefined, 4));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -50,28 +52,72 @@ namespace Versions {
|
||||
}
|
||||
}
|
||||
|
||||
export function publish(typing: TypingsData, settings: PublishSettings): boolean {
|
||||
const args: string[] = [
|
||||
'publish',
|
||||
// packagePath,
|
||||
'--access public'
|
||||
];
|
||||
function mkdir(p: string) {
|
||||
try {
|
||||
fs.statSync(p);
|
||||
} catch(e) {
|
||||
fs.mkdirSync(p);
|
||||
}
|
||||
}
|
||||
|
||||
const content = fs.readFileSync(typing.definitionFilename, 'utf-8');
|
||||
function patchDefinitionFile(input: string): string {
|
||||
const pathToLibrary = /\/\/\/ <reference path="..\/(\w.+)\/.+ \/>/gm;
|
||||
let output = input.replace(pathToLibrary, '/// <reference library="$1" />');
|
||||
return output;
|
||||
}
|
||||
|
||||
return Versions.performUpdate(typing.folder, content, version => {
|
||||
const packageJson = createPackageJSON(typing, settings, version);
|
||||
export function publish(typing: TypingsData, settings: PublishSettings): { log: string[] } {
|
||||
const log: string[] = [];
|
||||
|
||||
log.push(`Possibly publishing ${typing.libraryName}`);
|
||||
|
||||
let allContent = '';
|
||||
// Make the file ordering deterministic so the hash doesn't jump around for no reason
|
||||
typing.files.sort();
|
||||
for(const file of typing.files) {
|
||||
allContent = allContent + fs.readFileSync(path.join(typing.root, file), 'utf-8');
|
||||
}
|
||||
|
||||
const actualPackageName = typing.packageName.toLowerCase();
|
||||
|
||||
const didUpdate = Versions.performUpdate(actualPackageName, allContent, version => {
|
||||
log.push('Generate package.json and README.md; ensure output path exists');
|
||||
const packageJson = JSON.stringify(createPackageJSON(typing, settings, version), undefined, 4);
|
||||
const readme = createReadme(typing);
|
||||
|
||||
const outputPath = path.join(settings.outputPath, typing.folder);
|
||||
if (!fs.exists(outputPath)) {
|
||||
fs.mkdirSync(outputPath);
|
||||
}
|
||||
const outputPath = path.join(settings.outputPath, actualPackageName);
|
||||
mkdir(outputPath);
|
||||
|
||||
fs.writeFileSync(path.join(outputPath, 'package.json'), packageJson, 'utf-8');
|
||||
fs.writeFileSync(path.join(outputPath, 'README.md'), readme, 'utf-8');
|
||||
fs.writeFileSync(path.join(outputPath, path.basename(typing.definitionFilename)), fs.readFileSync(typing.definitionFilename));
|
||||
|
||||
typing.files.forEach(file => {
|
||||
log.push(`Copy and patch ${file}`);
|
||||
let content = fs.readFileSync(path.join(typing.root, file), 'utf-8');
|
||||
content = patchDefinitionFile(file);
|
||||
fs.writeFileSync(path.join(outputPath, file), file);
|
||||
});
|
||||
|
||||
const args: string[] = ['npm', 'publish', path.resolve(outputPath), '--access public'];
|
||||
const cmd = args.join(' ');
|
||||
log.push(`Run ${cmd}`);
|
||||
try {
|
||||
const result = <string>child_process.execSync(cmd, { encoding: 'utf-8' });
|
||||
log.push(`Ran successfully`);
|
||||
log.push(result);
|
||||
return true;
|
||||
} catch(e) {
|
||||
log.push(`!!! Publish failed`);
|
||||
log.push(JSON.stringify(e));
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
if (!didUpdate) {
|
||||
log.push('Package was already up-to-date');
|
||||
}
|
||||
|
||||
return { log };
|
||||
}
|
||||
|
||||
|
||||
@@ -81,7 +127,7 @@ function createPackageJSON(typing: TypingsData, settings: PublishSettings, fileV
|
||||
typing.libraryDependencies.forEach(d => dependencies[`@${settings.scopeName}/${d}`] = '*');
|
||||
|
||||
return ({
|
||||
name: `@${settings.scopeName}/${typing.packageName}`,
|
||||
name: `@${settings.scopeName}/${typing.packageName.toLowerCase()}`,
|
||||
version: `${typing.libraryMajorVersion}.${typing.libraryMinorVersion}.${fileVersion}`,
|
||||
description: `Type definitions for ${typing.libraryName} from ${typing.sourceRepoURL}`,
|
||||
main: '', //? index.js',
|
||||
@@ -99,12 +145,7 @@ function createReadme(typing: TypingsData) {
|
||||
lines.push(`This package contains type definitions for ${typing.libraryName}.`)
|
||||
if (typing.projectName) {
|
||||
lines.push('');
|
||||
lines.push(`The project URL is ${typing.projectName}`);
|
||||
}
|
||||
|
||||
if (typing.hasNpmPackage) {
|
||||
lines.push('');
|
||||
lines.push(`The corresponding NPM package is https://www.npmjs.com/package/${typing.packageName}`);
|
||||
lines.push(`The project URL or description is ${typing.projectName}`);
|
||||
}
|
||||
|
||||
if (typing.authors) {
|
||||
@@ -113,15 +154,16 @@ function createReadme(typing: TypingsData) {
|
||||
}
|
||||
|
||||
lines.push('');
|
||||
lines.push(`Typings were exported from ${typing.sourceRepoURL} in the ${typing.folder} directory.`);
|
||||
lines.push(`Typings were exported from ${typing.sourceRepoURL} in the ${typing.packageName} directory.`);
|
||||
|
||||
lines.push('');
|
||||
lines.push(`Additional Details`)
|
||||
lines.push(` * Last updated: ${(new Date()).toUTCString()}`);
|
||||
lines.push(` * Typings kind: ${DefinitionFileKind[typing.type]}`);
|
||||
lines.push(` * Typings kind: ${typing.kind}`);
|
||||
lines.push(` * Library Dependencies: ${typing.libraryDependencies.length ? typing.libraryDependencies.join(', ') : 'none'}`);
|
||||
lines.push(` * Module Dependencies: ${typing.moduleDependencies.length ? typing.moduleDependencies.join(', ') : 'none'}`);
|
||||
lines.push(` * Globals: ${typing.globals.length ? typing.globals.join(', ') : 'none'}`);
|
||||
lines.push(` * Global values: ${typing.globals.length ? typing.globals.join(', ') : 'none'}`);
|
||||
lines.push('');
|
||||
|
||||
return lines.join('\r\n');
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/// <reference path="typings/node/node.d.ts" />
|
||||
|
||||
import * as parser from './definition-parser';
|
||||
import * as publisher from './definition-publisher';
|
||||
|
||||
import fs = require('fs');
|
||||
import path = require('path');
|
||||
@@ -14,29 +15,39 @@ const OutputPath = './output/';
|
||||
const summaryLog: string[] = [];
|
||||
const detailedLog: string[] = [];
|
||||
const outcomes: { [s: string]: number } = {};
|
||||
const kinds: { [s: string]: number } = {};
|
||||
|
||||
const publishSettings: publisher.PublishSettings = { outputPath: './output', scopeName: 'ryancavanaugh' };
|
||||
|
||||
function recordKind(s: string) {
|
||||
kinds[s] = (kinds[s] || 0) + 1;
|
||||
}
|
||||
|
||||
function recordOutcome(s: string) {
|
||||
outcomes[s] = (outcomes[s] || 0) + 1;
|
||||
}
|
||||
|
||||
interface VersionMap {
|
||||
[typingsPackageName: string]: string;
|
||||
}
|
||||
|
||||
function processDir(folderPath: string, name: string) {
|
||||
detailedLog.push(`## ${name}`);
|
||||
|
||||
const info = parser.getTypingInfo(folderPath);
|
||||
|
||||
if (parser.isSuccess(info)) {
|
||||
detailedLog.push('### Succeeded');
|
||||
detailedLog.push(`Detected a ${parser.DefinitionFileKind[info.data.type]} typing definition.`);
|
||||
detailedLog.push('### File Parse Succeeded');
|
||||
detailedLog.push(`Detected a ${info.data.kind} typing definition.`);
|
||||
detailedLog.push('```js');
|
||||
detailedLog.push(JSON.stringify(info.data, undefined, 4));
|
||||
detailedLog.push('```');
|
||||
recordOutcome(`Succeeded (${parser.DefinitionFileKind[info.data.type]})`);
|
||||
recordOutcome(`Succeeded (${info.data.kind})`);
|
||||
recordKind(info.data.kind);
|
||||
|
||||
detailedLog.push('### Publish');
|
||||
const publishLog = publisher.publish(info.data, publishSettings);
|
||||
for(const line of publishLog.log) {
|
||||
detailedLog.push(` > ${line}\r\n\r\n`);
|
||||
}
|
||||
} else if(parser.isFail(info)) {
|
||||
detailedLog.push('### Failed');
|
||||
detailedLog.push('### File Parse Failed');
|
||||
switch (info.rejectionReason) {
|
||||
case parser.RejectionReason.BadFileFormat:
|
||||
recordOutcome('Failed: Bad file format');
|
||||
@@ -56,7 +67,7 @@ function processDir(folderPath: string, name: string) {
|
||||
}
|
||||
|
||||
detailedLog.push('### Parser Log');
|
||||
for(const line of info.log) detailedLog.push('> ' + line);
|
||||
for(const line of info.log) detailedLog.push('> ' + line + '\r\n');
|
||||
detailedLog.push('');
|
||||
}
|
||||
|
||||
@@ -76,11 +87,20 @@ function main() {
|
||||
|
||||
folders.forEach(s => processDir(s.path, s.name));
|
||||
|
||||
summaryLog.push('\r\n### Overall Results');
|
||||
summaryLog.push('\r\n### Overall Results\r\n');
|
||||
|
||||
summaryLog.push(' * Pass / fail');
|
||||
const outcomeKeys = Object.keys(outcomes);
|
||||
outcomeKeys.sort();
|
||||
outcomeKeys.forEach(k => {
|
||||
summaryLog.push(` * ${k}: ${outcomes[k]}`);
|
||||
summaryLog.push(` * ${k}: ${outcomes[k]}`);
|
||||
});
|
||||
|
||||
summaryLog.push(' * Typing Kind');
|
||||
const typingKeys = Object.keys(kinds);
|
||||
typingKeys.sort();
|
||||
typingKeys.forEach(k => {
|
||||
summaryLog.push(` * ${k}: ${kinds[k]}`);
|
||||
});
|
||||
|
||||
const logmd = summaryLog.join('\r\n') + '\r\n\r\n# Detailed Report\r\n\r\n' + detailedLog.join('\r\n');
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
"typings/tsd.d.ts"
|
||||
],
|
||||
"compilerOptions": {
|
||||
"module": "commonjs"
|
||||
"module": "commonjs",
|
||||
"noImplicitAny": true
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user