Skip to content

Commit

Permalink
See #105. WIP Improve OptionValues type, add beautifiers property
Browse files Browse the repository at this point in the history
  • Loading branch information
Glavin001 committed Mar 5, 2019
1 parent 3535d7b commit 0e31346
Show file tree
Hide file tree
Showing 8 changed files with 303 additions and 23 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@
"dev": "tsc --watch",
"copy-languages-json": "cp src/languages.json dist/src/languages.json",
"compile": "tsc",
"build": "npm-run-all compile copy-languages-json update-type-defs",
"build": "npm-run-all compile copy-languages-json update-generated",
"clean": "rimraf dist/",
"prepublishOnly": "npm run build",
"docs": "typedoc --out docs --module commonjs --readme README.md --name Unibeautify src",
"lint": "tslint '{src,test,script}/**/*.ts'",
"lint-fix": "tslint --fix '{src,test,script}/**/*.ts'",
"update-type-defs": "node dist/scripts/update-type-defs.js dist/src/beautifier.d.ts",
"update-generated": "node dist/scripts/update-generated.js src/generated.ts",
"update-languages": "node dist/scripts/update-languages.js ./src/languages.json"
},
"repository": {
Expand Down
106 changes: 106 additions & 0 deletions scripts/update-generated.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// tslint:disable:newspaper-order no-shadowed-variable
import { Languages } from "../src/languages";
import { Options } from "../src/options";
import { readFileSync, writeFileSync } from "fs";
import { resolve } from "path";
// import { replaceInterface, replaceType } from "./utils";

const [, , dest] = process.argv;

if (!dest) {
console.error("Missing required arguments: destination.");
process.exit(1);
}

const destPath = resolve(process.cwd(), dest);
const originalContents = readFileSync(destPath).toString();

let newContents: string = originalContents;
newContents = updateBeautifierLanguageOptions(newContents);
newContents = updateBeautifierOptionName(newContents);
newContents = updateOptionValues(newContents);
newContents = updateBeautifierLanguageOptionComplex(newContents);

writeFileSync(destPath, newContents);
console.log(`Done writing to ${destPath}!`);

function updateBeautifierLanguageOptions(originalContents: string): string {
const fields: string[] = Languages.map(
language => ` "${language.name}"?: BeautifierLanguageOptions;`
);
const interfaceName = "BeautifierOptions";
const newInterfaceBody: string = ` "_"?: BeautifierLanguageOptions;\n${fields.join(
"\n"
)}`;
return replaceInterface(originalContents, interfaceName, newInterfaceBody);
}

function updateBeautifierOptionName(originalContents: string): string {
const optionNames = Object.keys(Options);
const enums = optionNames.map(name => `"${name}"`);
const newTypeBody = enums.join(" | ");
return replaceType(originalContents, "BeautifierOptionName", newTypeBody);
}

function updateOptionValues(originalContents: string): string {
const optionNames = Object.keys(Options);
const fields: string[] = optionNames.map(optionName => {
const option = Options[optionName];
const fieldType: string = typescriptTypeForOptionType(option.type);
return ` "${optionName}"?: ${fieldType};`;
});
const interfaceName = "OptionValues";
const newInterfaceBody: string = fields.join("\n");
return replaceInterface(originalContents, interfaceName, newInterfaceBody);
}

function updateBeautifierLanguageOptionComplex(
originalContents: string
): string {
const interfaceName = "BeautifierLanguageOptionComplex";
const optionNames = Object.keys(Options);
const fields: string[] = optionNames.map(optionName => {
const option = Options[optionName];
const valueType: string = typescriptTypeForOptionType(option.type);
const fieldType: string = `true | ((${optionName}: ${valueType}) => any) | BeautifierLanguageOption`;
return ` "${optionName}"?: ${fieldType};`;
});
const newInterfaceBody: string = fields.join("\n");
const newInterfaceContents: string = `export interface ${interfaceName} {
${newInterfaceBody}
}`;
return originalContents + "\n" + newInterfaceContents + "\n";
}

function typescriptTypeForOptionType(optionType: string): string {
switch (optionType) {
case "array":
return "any[]";
case "integer":
return "number";
default:
return optionType;
}
}

function replaceInterface(
originalContents: string,
interfaceName: string,
newInterfaceBody: string
): string {
return [originalContents, (
`export interface ${interfaceName} {
${newInterfaceBody}
}`
)].join("\n");
}

function replaceType(
originalContents: string,
typeName: string,
newTypeBody: string
): string {
return [originalContents, (
`export declare type ${typeName} = ${newTypeBody};`
)].join("\n");
}
20 changes: 20 additions & 0 deletions src/DependencyManager/DependencyManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
DependencyDefinition,
DependencyOptions,
} from "./Dependency";
import { BeautifierOptionName } from "../generated";

export class DependencyManager {
private static registry: DependencyRegistry = {};
Expand Down Expand Up @@ -84,10 +85,29 @@ export interface LanguageDependencyOptions {
[dependencyName: string]: DependencyOptions;
}

/*
export interface DependencyRegistry {
[beautifierName: string]: {
[dependencyName: string]: {
[optionsKey: string]: Dependency;
};
};
}
*/

export interface DependenciesForBeautifierRegistry {
[dependencyName: string]: {
[optionsKey: string]: Dependency;
// [optionName in BeautifierOptionName]: Dependency;
};
}

export interface DependencyRegistry {
[beautifierName: string]: DependenciesForBeautifierRegistry;
}

/*
export interface DependencyRegistry<EnabledBeautifiers extends keyof string[]> {
[beautifierName in EnabledBeautifiers]: DependenciesForBeautifierRegistry;
}
*/
117 changes: 109 additions & 8 deletions src/beautifier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,90 @@ import {
DependencyDefinition,
DependencyManager,
Badge,
DependencyRegistry,
DependenciesForBeautifierRegistry,
} from "./DependencyManager";
import { zipObject, unique } from "./utils";
import { BeautifierOptionName } from "./generated";
// tslint:disable-next-line:export-name
export { BeautifierOptionName };

/**
New name to rename the option (key) to.
Name of an option to configure for a beautifier.
*/
export type BeautifierOptionName = string;
// export type BeautifierOptionName = string;

// tslint:disable-next-line:max-line-length
// export type BeautifierOptionName = "align_assignments" | "arrow_parens" | "brace_style" | "break_chained_methods" | "comma_first" | "end_of_line" | "end_with_comma" | "end_with_newline" | "end_with_semicolon" | "force_indentation" | "identifier_case" | "indent_chained_methods" | "indent_char" | "indent_comments" | "indent_inner_html" | "indent_level" | "indent_scripts" | "indent_size" | "indent_style" | "indent_with_tabs" | "jslint_happy" | "jsx_brackets" | "keep_array_indentation" | "keyword_case" | "max_preserve_newlines" | "multiline_ternary" | "newline_before_tags" | "newline_between_rules" | "no_leading_zero" | "object_curly_spacing" | "pragma_insert" | "pragma_require" | "preserve_newlines" | "quotes" | "remove_trailing_whitespace" | "selector_separator_newline" | "space_after_anon_function" | "space_before_conditional" | "space_in_empty_paren" | "space_in_paren" | "typesafe_equality_operators" | "unescape_strings" | "unformatted" | "unindent_chained_methods" | "wrap_attributes" | "wrap_attributes_indent_size" | "wrap_line_length" | "wrap_prose";

/**
Function to process the given options and return a final option value.
*/
export type BeautifierOptionTransformFunction = (options: OptionValues) => any;
// export type BeautifierOptionTransformFunction = (options: OptionValues) => any;
// export type BeautifierOptionTransformFunction = (options: LanguageSpecificOptionValues) => any;

// export type BeautifierOptionTransformFunction<
// OptionNames extends keyof LanguageSpecificOptionValues
// > = (options: Pick<LanguageSpecificOptionValues, OptionNames>) => any;

export type BeautifierOptionTransformFunction = (options: Partial<LanguageSpecificOptionValues>) => any;

// export type BeautifierOptionTransformFunction<
// OptionNames extends BeautifierOptionName
// > = (options: Pick<LanguageSpecificOptionValues, OptionNames>) => any;

/**
Option that transforms one or more required options into a single value.
*/

/*
export type BeautifyOptionTransform<
SelectedBeautifierOptionNames extends BeautifierOptionName,
T extends SelectedBeautifierOptionNames[]
> = [
T,
BeautifierOptionTransformFunction<SelectedBeautifierOptionNames>
];
*/

/*
export type BeautifyOptionTransform<
SelectedBeautifierOptionNames extends BeautifierOptionName
> = [
SelectedBeautifierOptionNames[],
BeautifierOptionTransformFunction<SelectedBeautifierOptionNames>
];
*/

export type BeautifyOptionTransform = [
BeautifierOptionName[],
BeautifierOptionTransformFunction
BeautifierOptionTransformFunction,
];

/*
export type BeautifyOptionTransform<T> = T extends [
(infer SelectedBeautifierOptionNames extends BeautifierOptionName)[],
any
] ? ([
SelectedBeautifierOptionNames[],
BeautifierOptionTransformFunction<SelectedBeautifierOptionNames>
]) : never;
*/
/*
type BeautifyOptionTransform<T> = T extends { a: infer U, b: infer U } ? U : never;
type Foo<T> = T extends { a: infer U, b: infer U } ? U : never;
type Foo<T, U> = T extends { a: U, b: U } ? U : never;
*/

// const complexTransform: BeautifyOptionTransform<"indent_with_tabs" | "indent_size"> = [
// const complexTransform: BeautifyOptionTransform = [
// ["indent_with_tabs", "indent_size"],
// (optionValues) => optionValues.indent_with_tabs,
// ];

/**
Option that transforms a single option value with the same name.
*/
Expand Down Expand Up @@ -96,12 +161,48 @@ export interface BeautifierBeautifyData {
beautifierConfig?: ResolvedConfig;
}

export interface LanguageOptionValues {
[languageName: string]: OptionValues;
export type LanguageSpecificOptionValues = {
[optionName in BeautifierOptionName]?: any;
};

export interface BeautifierSpecificOptionValues {
prefer_beautifier_config?: boolean | string;
}

export interface BeautifierOptionValues {
[beautifierName: string]: BeautifierSpecificOptionValues;
}

export interface OptionValues {
[optionName: string]: any;
/*
export type OptionValues = {
beautifiers?: string[];
} & LanguageSpecificOptionValues & BeautifierOptionValues & DependencyRegistry;
*/

export type OptionValues = LanguageSpecificOptionValues & {
beautifiers?: string[];
} & {
// [beautifierName: string]: BeautifierSpecificOptionValues & DependenciesForBeautifierRegistry | string[] | undefined;
[beautifierName: string]: BeautifierSpecificOptionValues & DependenciesForBeautifierRegistry;
};

/*
const test: OptionValues = {
beautifiers: ["test"],
};
*/

/*
export type OptionValues<EnabledBeautifiers extends keyof string[]> = LanguageSpecificOptionValues
& BeautifierOptionValues
& DependencyRegistry<EnabledBeautifiers>
& {
beautifiers?: EnabledBeautifiers[];
};
*/

export interface LanguageOptionValues {
[languageName: string]: OptionValues;
}

/**
Expand Down Expand Up @@ -565,7 +666,7 @@ export class Unibeautify {
return {};
} else if (typeof beautifierOptions === "object") {
return Object.keys(beautifierOptions).reduce(
(acc: OptionValues, key: string) => {
(acc: OptionValues, key: BeautifierOptionName) => {
const option = beautifierOptions[key];
if (typeof option === "string") {
return {
Expand Down
49 changes: 49 additions & 0 deletions src/generated.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
export type BeautifierOptionName =
| "align_assignments"
| "arrow_parens"
| "brace_style"
| "break_chained_methods"
| "comma_first"
| "end_of_line"
| "end_with_comma"
| "end_with_newline"
| "end_with_semicolon"
| "force_indentation"
| "identifier_case"
| "indent_chained_methods"
| "indent_char"
| "indent_comments"
| "indent_inner_html"
| "indent_level"
| "indent_scripts"
| "indent_size"
| "indent_style"
| "indent_with_tabs"
| "jslint_happy"
| "jsx_brackets"
| "keep_array_indentation"
| "keyword_case"
| "max_preserve_newlines"
| "multiline_ternary"
| "newline_before_tags"
| "newline_between_rules"
| "no_leading_zero"
| "object_curly_spacing"
| "pragma_insert"
| "pragma_require"
| "preserve_newlines"
| "quotes"
| "remove_trailing_whitespace"
| "selector_separator_newline"
| "space_after_anon_function"
| "space_before_conditional"
| "space_in_empty_paren"
| "space_in_paren"
| "typesafe_equality_operators"
| "unescape_strings"
| "unformatted"
| "unindent_chained_methods"
| "wrap_attributes"
| "wrap_attributes_indent_size"
| "wrap_line_length"
| "wrap_prose";
10 changes: 6 additions & 4 deletions test/beautifier/beautifier.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,23 +178,25 @@ test("should successfully transform option values for beautifier", () => {
name: "TestBeautify",
options: {
[lang1.name]: {
basicTransform: num => num + 1,
basicTransform: (num: number) => num + 1,
complexTransform: [
// ["indent_char", "indent_size", "indent_with_tabs"],
// (optionValues) => optionValues.indent_char + optionValues.indent_size,
["value1", "basicTransform"],
optionValues => optionValues.value1 + optionValues.basicTransform,
(optionValues: any) => optionValues.value1 + optionValues.basicTransform,
],
isUndefined: undefined,
renamed1: "value1",
value1: true,
value2: false,
willBeReplaced: "value1",
},
} as any,
[lang2.name]: true,
},
};
unibeautify.loadBeautifier(beautifier);

const options = {
const options: any = {
basicTransform: 2,
value1: 123,
};
Expand Down
Loading

0 comments on commit 0e31346

Please sign in to comment.