Publish work

This commit is contained in:
Ryan Cavanaugh
2016-03-21 21:59:41 -07:00
committed by Andrew Branch
parent 67f795f03d
commit c3f9e176a7
4 changed files with 286 additions and 168 deletions

View File

@@ -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;
}
}

View File

@@ -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');
}

View File

@@ -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');

View File

@@ -6,6 +6,7 @@
"typings/tsd.d.ts"
],
"compilerOptions": {
"module": "commonjs"
"module": "commonjs",
"noImplicitAny": true
}
}