Improve and distribute TypeScript typings

This commit is contained in:
David Siegel 2017-10-01 19:39:49 -07:00
Родитель 4b6525bf41
Коммит ec3d394575
31 изменённых файлов: 267 добавлений и 168 удалений

1
.gitignore поставляемый
Просмотреть файл

@ -19,3 +19,4 @@ test/elm/QuickType.elm
*.log
/test/elm/libsysconfcpus/
/test/runs
/dist

3
.vscode/settings.json поставляемый
Просмотреть файл

@ -1,6 +1,7 @@
// Place your settings in this file to overwrite default and user settings.
{
"purescript.addNpmPath": true,
"purescript.buildCommand": "pulp build --build-path dist -- --json-errors",
"editor.formatOnSave": true,
"search.exclude": {
"**/.git": true,
@ -17,4 +18,4 @@
"cli/dist": true
},
"java.configuration.updateBuildConfiguration": "automatic"
}
}

18
@types/Config.d.ts поставляемый Normal file
Просмотреть файл

@ -0,0 +1,18 @@
type Json = object;
type IRTypeable = Json | string;
declare namespace Config {
export type TopLevelConfig =
| { name: string; samples: IRTypeable[] }
| { name: string; schema: Json };
export interface Config {
language: string;
topLevels: TopLevelConfig[];
inferMaps?: boolean;
rendererOptions?: { [name: string]: string };
}
}
export = Config;
export as namespace Config;

7
@types/Core.d.ts поставляемый Normal file
Просмотреть файл

@ -0,0 +1,7 @@
declare namespace Core {
export type SourceCode = string;
export type ErrorMessage = string;
}
export = Core;
export as namespace Core;

10
@types/Data.Either.d.ts поставляемый Normal file
Просмотреть файл

@ -0,0 +1,10 @@
declare namespace Data_Either {
export interface Either<L, R> {}
export function isRight<T, U>(either: Either<T, U>): boolean;
export function isLeft<T, U>(either: Either<T, U>): boolean;
export function fromRight<T, U>(partial: any): (either: Either<T, U>) => U;
}
export = Data_Either;
export as namespace Data_Either;

9
@types/Data.Maybe.d.ts поставляемый Normal file
Просмотреть файл

@ -0,0 +1,9 @@
declare namespace Data_Maybe {
export interface Maybe<T> {}
export function isJust<T>(maybe: Maybe<T>): boolean;
export function fromJust<T>(unused: any): (maybe: Maybe<T>) => T;
export const fromMaybe: <T>(def: T) => (maybe: Maybe<T>) => T;
}
export = Data_Maybe;
export as namespace Data_Maybe;

13
@types/Doc.d.ts поставляемый Normal file
Просмотреть файл

@ -0,0 +1,13 @@
import { OptionSpecification } from "./Options";
declare namespace Doc {
export interface Renderer {
displayName: string;
names: [string];
extension: string;
aceMode: string;
options: [OptionSpecification];
}
}
export = Doc;
export as namespace Doc;

10
@types/Language.Renderers.d.ts поставляемый Normal file
Просмотреть файл

@ -0,0 +1,10 @@
import { Renderer } from "./Doc";
import { Maybe } from "./Data.Maybe";
declare namespace Language_Renderers {
export const all: Renderer[];
export function rendererForLanguage(language: string): Maybe<Renderer>;
}
export = Language_Renderers;
export as namespace Language_Renderers;

20
@types/Main.d.ts поставляемый Normal file
Просмотреть файл

@ -0,0 +1,20 @@
import { Config } from "./Config";
import { Either } from "./Data.Either";
import { ErrorMessage, SourceCode } from "./Core";
declare namespace Main {
export function main(config: Config): Either<ErrorMessage, SourceCode>;
export function mainWithOptions(options: {
[name: string]: string;
}): ((config: Config) => Either<ErrorMessage, SourceCode>);
export function urlsFromJsonGrammar(
json: object
): Either<string, { [key: string]: string[] }>;
export const intSentinel: string;
}
export = Main;
export as namespace Main;

34
@types/Options.d.ts поставляемый Normal file
Просмотреть файл

@ -0,0 +1,34 @@
import { Maybe } from "./Data.Maybe";
declare namespace Options {
export interface BooleanValue {
value0: boolean;
}
export interface StringValue {
value0: string;
}
export interface EnumValue {
value0: number;
value1: string[];
}
export type OptionValue = BooleanValue | StringValue | EnumValue;
export interface OptionSpecification {
name: string;
description: string;
typeLabel: string;
default: OptionValue;
}
export const valueType: (
value: OptionValue
) => "BooleanValue" | "StringValue" | "EnumValue";
export const stringValue: (value: OptionValue) => Maybe<string>;
}
export = Options;
export as namespace Options;

7
cli/Doc.d.ts поставляемый
Просмотреть файл

@ -1,7 +0,0 @@
interface Renderer {
displayName: string;
names: [string];
extension: string;
aceMode: string;
options: [OptionSpecification];
}

27
cli/Main.d.ts поставляемый
Просмотреть файл

@ -1,27 +0,0 @@
type SourceCode = string;
type ErrorMessage = string;
interface Main {
main(config: Config): Either<ErrorMessage, SourceCode>;
mainWithOptions(options: {
[name: string]: string;
}): ((config: Config) => Either<ErrorMessage, SourceCode>);
urlsFromJsonGrammar(
json: object
): Either<string, { [key: string]: string[] }>;
intSentinel: string;
}
type Json = object;
type IRTypeable = Json | string;
type TopLevelConfig =
| { name: string; samples: IRTypeable[] }
| { name: string; schema: Json };
interface Config {
language: string;
topLevels: TopLevelConfig[];
inferMaps?: boolean;
rendererOptions?: { [name: string]: string };
}

5
cli/Options.d.ts поставляемый
Просмотреть файл

@ -1,5 +0,0 @@
interface OptionSpecification {
name: string;
description: string;
typeLabel: string;
}

2
cli/Prelude.d.ts поставляемый
Просмотреть файл

@ -1,2 +0,0 @@
type Either<L, R> = { value0: L | R };
type Maybe<T> = { value0?: T };

4
cli/Renderers.d.ts поставляемый
Просмотреть файл

@ -1,4 +0,0 @@
interface Renderers {
all: Renderer[];
rendererForLanguage(language: string): Maybe<Renderer>;
}

Просмотреть файл

@ -1,21 +0,0 @@
export function isRight<T, U>(either: Either<T, U>): boolean {
return either.constructor.name == "Right";
}
export function isLeft<T, U>(either: Either<T, U>): boolean {
return either.constructor.name == "Left";
}
export function get<T, U>(either: Either<T, U>): T | U {
return either.value0;
}
export function fromRight<T>(either: Either<string, T>): T | never {
let result = get(either);
if (isLeft(either)) {
console.error(result);
return process.exit(1);
} else {
return <T>result;
}
}

Просмотреть файл

@ -1,8 +0,0 @@
export function isJust<T>(maybe: Maybe<T>): boolean {
return maybe.constructor.name === "Just";
}
export function fromJust<T>(maybe: Maybe<T>): T {
if (!maybe.value0) throw "fromJust invoked on Nothing";
return maybe.value0;
}

10
cli/purescript.ts Normal file
Просмотреть файл

@ -0,0 +1,10 @@
import * as Either from "Data.Either";
import * as Maybe from "Data.Maybe";
export function fromJust<T>(maybe: Maybe.Maybe<T>): T {
return Maybe.fromJust<T>(null)(maybe);
}
export function fromRight<L, R>(either: Either.Either<L, R>): R {
return Either.fromRight<L, R>(null)(either);
}

Просмотреть файл

@ -1,13 +1,20 @@
import * as fs from "fs";
import * as path from "path";
import * as process from "process";
import * as Either from "./either";
import * as Maybe from "./maybe";
import { psRequire } from "./require";
import * as Either from "Data.Either";
import * as Maybe from "Data.Maybe";
// These are simplified, uncurried versions of Either.fromRight, etc.
import { fromRight, fromJust } from "./purescript";
import * as _ from "lodash";
const Main: Main = psRequire("Main");
const Renderers: Renderers = psRequire("Language.Renderers");
import * as Main from "Main";
import { Config } from "Config";
import { Renderer } from "Doc";
import * as Renderers from "Language.Renderers";
import { ErrorMessage, SourceCode } from "Core";
const makeSource = require("stream-json");
const Assembler = require("stream-json/utils/Assembler");
@ -232,7 +239,7 @@ class Run {
console.error(`'${lang}' is not yet supported as an output language.`);
process.exit(1);
}
return Maybe.fromJust(maybe);
return fromJust(maybe);
};
renderSamplesOrSchemas = (
@ -254,7 +261,7 @@ class Run {
rendererOptions: this.options.rendererOptions
};
return Either.fromRight(Main.main(config));
return fromRight(Main.main(config));
};
splitAndWriteJava = (dir: string, str: string) => {
@ -391,7 +398,7 @@ class Run {
usage();
} else if (this.options.srcUrls) {
let json = JSON.parse(fs.readFileSync(this.options.srcUrls, "utf8"));
let jsonMap = Either.fromRight(Main.urlsFromJsonGrammar(json));
let jsonMap = fromRight(Main.urlsFromJsonGrammar(json));
this.renderAndOutput(
await this.mapValues(jsonMap, this.parseFileOrUrlArray)
);

Просмотреть файл

@ -1,14 +0,0 @@
export function tryRequire(...paths: string[]): any {
for (let path of paths) {
try {
return require(path);
} catch (e) {
continue;
}
}
throw "No path could be required";
}
export function psRequire<T>(path: string): T {
return tryRequire(`../output/${path}`, `./${path}`);
}

Просмотреть файл

@ -1,10 +1,15 @@
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"lib": ["es2015"],
"outDir": "../output",
"baseUrl": ".",
"allowJs": false,
"declaration": true,
"typeRoots": ["../node_modules/@types"],
"strictNullChecks": true
},
"include": ["*.ts"]
"strictNullChecks": true,
"paths": {
"*": ["../dist/*"]
}
}
}

70
package-lock.json сгенерированный
Просмотреть файл

@ -16,6 +16,16 @@
"integrity": "sha512-wbKN0MB4XsjdnSE04HiCzLoBDirGCM6zXrqavSj44nZnPFYpnrTF64E9O6Xmf0ca/IuKK/BHUcXwMiwk92gW6Q==",
"dev": true
},
"JSONStream": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.1.tgz",
"integrity": "sha1-cH92HgHa6eFvG8+TcDt4xwlmV5o=",
"dev": true,
"requires": {
"jsonparse": "1.3.1",
"through": "2.3.8"
}
},
"acorn": {
"version": "4.0.13",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz",
@ -443,9 +453,9 @@
"integrity": "sha1-+GzWzvT1MAyOY+B6TVEvZfv/RTE=",
"dev": true,
"requires": {
"JSONStream": "1.3.1",
"combine-source-map": "0.7.2",
"defined": "1.0.0",
"JSONStream": "1.3.1",
"through2": "2.0.3",
"umd": "3.0.1"
}
@ -473,6 +483,7 @@
"integrity": "sha1-tanJAgJD8McORnW+yCI7xifkFc4=",
"dev": true,
"requires": {
"JSONStream": "1.3.1",
"assert": "1.4.1",
"browser-pack": "6.0.2",
"browser-resolve": "1.11.2",
@ -494,7 +505,6 @@
"https-browserify": "0.0.1",
"inherits": "2.0.3",
"insert-module-globals": "7.0.1",
"JSONStream": "1.3.1",
"labeled-stream-splicer": "2.0.0",
"module-deps": "4.1.1",
"os-browserify": "0.1.2",
@ -595,18 +605,12 @@
"integrity": "sha1-BxPLdYckemMqnwjPG9FpuHi2Koo=",
"dev": true,
"requires": {
"browserify-cache-api": "3.0.1",
"JSONStream": "0.10.0",
"browserify-cache-api": "3.0.1",
"through2": "2.0.3",
"xtend": "4.0.1"
},
"dependencies": {
"jsonparse": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-0.0.5.tgz",
"integrity": "sha1-MwVCrT8KZUZlt3jz6y2an6UHrGQ=",
"dev": true
},
"JSONStream": {
"version": "0.10.0",
"resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-0.10.0.tgz",
@ -616,6 +620,12 @@
"jsonparse": "0.0.5",
"through": "2.3.8"
}
},
"jsonparse": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-0.0.5.tgz",
"integrity": "sha1-MwVCrT8KZUZlt3jz6y2an6UHrGQ=",
"dev": true
}
}
},
@ -2558,14 +2568,6 @@
}
}
},
"string_decoder": {
"version": "1.0.1",
"bundled": true,
"dev": true,
"requires": {
"safe-buffer": "5.0.1"
}
},
"string-width": {
"version": "1.0.2",
"bundled": true,
@ -2576,6 +2578,14 @@
"strip-ansi": "3.0.1"
}
},
"string_decoder": {
"version": "1.0.1",
"bundled": true,
"dev": true,
"requires": {
"safe-buffer": "5.0.1"
}
},
"stringstream": {
"version": "0.0.5",
"bundled": true,
@ -3249,10 +3259,10 @@
"integrity": "sha1-wDv04BywhtW15azorQr+eInWOMM=",
"dev": true,
"requires": {
"JSONStream": "1.3.1",
"combine-source-map": "0.7.2",
"concat-stream": "1.5.2",
"is-buffer": "1.1.5",
"JSONStream": "1.3.1",
"lexical-scope": "1.2.0",
"process": "0.11.10",
"through2": "2.0.3",
@ -3580,16 +3590,6 @@
"integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=",
"dev": true
},
"JSONStream": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.1.tgz",
"integrity": "sha1-cH92HgHa6eFvG8+TcDt4xwlmV5o=",
"dev": true,
"requires": {
"jsonparse": "1.3.1",
"through": "2.3.8"
}
},
"jsprim": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
@ -4029,6 +4029,7 @@
"integrity": "sha1-IyFYM/HaE/1gbMuAh7RIUty4If0=",
"dev": true,
"requires": {
"JSONStream": "1.3.1",
"browser-resolve": "1.11.2",
"cached-path-relative": "1.0.1",
"concat-stream": "1.5.2",
@ -4036,7 +4037,6 @@
"detective": "4.5.0",
"duplexer2": "0.1.4",
"inherits": "2.0.3",
"JSONStream": "1.3.1",
"parents": "1.0.1",
"readable-stream": "2.0.6",
"resolve": "1.4.0",
@ -5101,18 +5101,18 @@
"readable-stream": "2.0.6"
}
},
"string_decoder": {
"version": "0.10.31",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
"integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
"dev": true
},
"string-stream": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/string-stream/-/string-stream-0.0.7.tgz",
"integrity": "sha1-z83oJ5n6YvMDQpqqeTNu6INDMv4=",
"dev": true
},
"string_decoder": {
"version": "0.10.31",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
"integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
"dev": true
},
"stringstream": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz",

Просмотреть файл

@ -2,6 +2,8 @@
"name": "quicktype",
"version": "0.10.8",
"license": "Apache-2.0",
"main": "quicktype.js",
"types": "quicktype.d.ts",
"repository": "https://github.com/quicktype/quicktype",
"scripts": {
"pub": "script/publish.sh",

Просмотреть файл

@ -1,12 +1,46 @@
#!/bin/sh
OUTDIR=dist
npm install --ignore-scripts
bower install --allow-root
pulp build -- --source-maps --stash --censor-warnings
pulp build --build-path $OUTDIR -- --source-maps --stash --censor-warnings
# Move TypeScript typings next to PureScript JavaScript modules
for typeFile in @types/*.d.ts; do
filename=$(basename $typeFile)
module="${filename%%.d.ts}"
cat $typeFile \
| sed -e "s/from \"\.\/\(.*\)\"/from \"\.\.\/\/\1\"/g" \
> $OUTDIR/$module/index.d.ts
done
tsc --project cli/tsconfig.json
BIN=output/quicktype.js
echo "#!/usr/bin/env node" > $BIN.bak
cat $BIN >> $BIN.bak
mv $BIN.bak $BIN
# Rewrite `require("Module")` as `require("./Module")` for PureScript modules
#
# TODO I hate this, but after two weeks trying to make TypeScript, PureScript,
# and JavaScript play nicely together, I'm saying "fuck it".
#
# Imports have to be absolute to compile, but relative to run. Seriously, fuck it.
for typeFile in @types/*.d.ts; do
filename=$(basename $typeFile)
module="${filename%%.d.ts}"
# TODO this currently only works for top-level files
for script in cli/*.js; do
sed -i -e "s/require(\"$module\")/require(\"\.\/$module\")/g" $script
done
for script in cli/*.d.ts; do
sed -i -e "s/from \"$module\"/from \"\.\/$module\"/g" $script
done
done
# Distribute README, TypeScript, etc.
rm -f cli/*-e # remove artifacts from sed(?)
cp cli/*.js cli/*.d.ts $OUTDIR/
(echo "#!/usr/bin/env node"; cat cli/quicktype.js) > $OUTDIR/quicktype.js
chmod +x $OUTDIR/quicktype.js
rm -f cli/*.js cli/*.d.ts

Просмотреть файл

@ -1,22 +1,20 @@
#!/bin/bash
OUTDIR=dist
# If not on CI, do a clean build
if [ -z "$CI" ]; then
rm -rf output
rm -rf $OUTDIR
npm run build
fi
# Copy npm package files into output/
mkdir -p output
cp LICENSE* package*.json cli/README.md output/
cd output
# This is pretty silly, but we do it to make Travis deploy work
mkdir script
echo "#\!/bin/bash" > script/build.sh
chmod +x script/build.sh
cp -r LICENSE* package*.json cli/README.md $OUTDIR/
cd $OUTDIR
# If not on CI, publish directly
if [ -z "$CI" ]; then
npm publish
npm publish \
--ignore-scripts # Don't rebuild
fi

Просмотреть файл

@ -1,3 +1,10 @@
#!/bin/bash
npx ts-node --project cli/tsconfig.json cli/quicktype.ts $@
err() {
echo "$@" 1>&2
}
err "Building quicktype..."
npm run build &>/dev/null
node dist/quicktype.js $@

Просмотреть файл

@ -10,10 +10,13 @@ module Options
, enumOption
, makeOptionValues
, lookupOptionValue
, valueType
, stringValue
) where
import Prelude
import Data.Array ((!!))
import Data.Array as A
import Data.Foldable (elem, intercalate)
import Data.Maybe (Maybe(..), fromJust)
@ -45,6 +48,18 @@ type OptionValueExtractor a = OptionValue -> a
type Option a = { specification :: OptionSpecification, extractor :: OptionValueExtractor a }
valueType :: OptionValue -> String
valueType = case _ of
BooleanValue _ -> "BooleanValue"
StringValue _ -> "StringValue"
EnumValue _ _ -> "EnumValue"
stringValue :: OptionValue -> Maybe String
stringValue = case _ of
BooleanValue b -> Just $ show b
StringValue s -> Just s
EnumValue i xs -> xs !! i
-- FIXME: error handling!
makeOptionValues :: OptionSpecifications -> StrMap String -> OptionValues
makeOptionValues optionSpecifications optionStrings =

Просмотреть файл

@ -1,14 +0,0 @@
module Samples where
samples :: Array String
samples = [
"getting-started.json",
"pokedex.json",
"spotify-album.json",
"kitchen-sink.json",
"bitcoin-block.json",
"reddit.json",
"github-events.json",
"us-avg-temperatures.json",
"us-senators.json"
]

Просмотреть файл

@ -79,7 +79,7 @@ async function main(sources: string[]) {
function testCLI() {
console.log(`* CLI sanity check`);
const qt = "node output/quicktype.js";
const qt = "node dist/quicktype.js";
exec(`${qt} --help`);
}

Просмотреть файл

@ -4,5 +4,5 @@
"lib": ["es2015"],
"strictNullChecks": true
},
"include": ["*.ts", "../cli/*.ts"]
"include": ["*.ts", "../dist/*.js", "../dist/*.d.ts"]
}

Просмотреть файл

@ -2,7 +2,7 @@
import * as fs from "fs";
import { main as quicktype_, Options } from "../cli/quicktype";
import { main as quicktype_, Options } from "../dist/quicktype";
import * as languages from "./languages";
import deepEquals from "./lib/deepEquals";