Skip to content

Commit

Permalink
Merge pull request #18 from samchon/v2.0
Browse files Browse the repository at this point in the history
Close #14 and Close #17
  • Loading branch information
samchon authored Apr 20, 2022
2 parents de312e6 + 131b80f commit 7740415
Show file tree
Hide file tree
Showing 11 changed files with 222 additions and 141 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "typescript-json",
"version": "2.0.1",
"version": "2.0.2",
"description": "Faster JSON stringify with only one line",
"main": "lib/index.js",
"typings": "lib/index.d.ts",
Expand Down
139 changes: 139 additions & 0 deletions src/factories/FunctionFactory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import crypto from "crypto";
import path from "path";
import ts from "typescript";

import { JsonFactory } from "../factories/JsonFactory";
import { SchemaFactory } from "../factories/SchemaFactory";
import { IProject } from "../structures/IProject";
import { ISchema } from "../structures/ISchema";

export namespace FunctionFactory
{
export type Closure =
(
project: IProject,
expression: ts.CallExpression,
type: ts.Type | null
) => ts.Expression;

export function generate
(
project: IProject,
expression: ts.CallExpression
): Closure | null
{
//----
// VALIDATIONS
//----
// SIGNATURE
const signature: ts.Signature | undefined = project.checker.getResolvedSignature(expression);
if (!signature || !signature.declaration)
return null;

// EXACT FILE
const file: string = path.resolve(signature.declaration.getSourceFile().fileName);
if (file !== LIB_PATH && file !== SRC_PATH)
return null;

// FIND FUNCTION
const name: string = project.checker.getTypeAtLocation(signature.declaration).symbol.name;
const generator: IGenerator | undefined = FUNCTORS[name];

if (generator === undefined)
return null;
else if (expression.arguments.length !== generator.count)
return null;

// RETURNS
return generator.argument();
}

function argue_stringify
(
project: IProject,
expression: ts.CallExpression,
type: ts.Type | null
): ts.ArrayLiteralExpression
{
if (type === null)
{
const top: ts.Expression = expression.arguments[0]!
type = project.checker.getTypeAtLocation(top);
}

const app: ISchema.IApplication | null = SchemaFactory.generate(project.checker, type);
const tuple: ts.ArrayLiteralExpression = JsonFactory.application(app);
const script: string = project.printer.printNode
(
ts.EmitHint.Unspecified,
tuple,
expression.getSourceFile()
);
const key: string = crypto
.createHash("sha256")
.update(script)
.digest("base64");

return ts.factory.createArrayLiteralExpression
([
ts.factory.createStringLiteral(key),
ts.factory.createArrowFunction
(
undefined,
undefined,
[],
undefined,
undefined,
tuple
)
]);
}

function argue_stringifier
(
project: IProject,
expression: ts.CallExpression,
type: ts.Type | null
): ts.ArrowFunction
{
if (type === null)
{
const file: ts.SourceFile = expression.getSourceFile();
const { line, character } = file.getLineAndCharacterOfPosition(expression.pos);

throw new Error(`Error on TSON.createStringifier(): the generic argument must be specified - ${file.fileName}:${line + 1}:${character + 1}.`);
}

const app: ISchema.IApplication | null = SchemaFactory.generate(project.checker, type);
const tuple: ts.ArrayLiteralExpression = JsonFactory.application(app);

return ts.factory.createArrowFunction
(
undefined,
undefined,
[],
undefined,
undefined,
tuple
);
}

interface IGenerator
{
count: number;
argument: () => Closure;
}

const LIB_PATH = path.resolve(path.join(__dirname, "..", "module.d.ts"));
const SRC_PATH = path.resolve(path.join(__dirname, "..", "module.ts"));
const FUNCTORS: Record<string, IGenerator> = {
stringify: {
count: 1,
argument: () => argue_stringify,
},
createStringifier: {
count: 0,
argument: () => argue_stringifier,
}
}
}
22 changes: 0 additions & 22 deletions src/functional/argue_stringifier.ts

This file was deleted.

42 changes: 0 additions & 42 deletions src/functional/argue_stringify.ts

This file was deleted.

69 changes: 0 additions & 69 deletions src/functional/get_json_function.ts

This file was deleted.

28 changes: 28 additions & 0 deletions src/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,34 @@ export function stringify<T>
return JsonMemory.stringify(key, closure)(input);
}

/**
* > You must configure the generic argument `T`.
*
* 2x faster `JSON.stringify()` function generator.
*
* Creates a function who can convert TypeScript value to the JSON (JavaSript Object Noation)
* string. directly. The returned function is two times faster than the native
* `JSON.stringify()`, because the function constructs a dedicated JSON string builder
* only for the type `T`.
*
* Also, the returned function is always reusable until you forget the returned function
* variable. Of course, it means that you've to manage the returned function by yourself.
* If you feel annoying for management, you can choose {@link stringify} instead. The
* {@link stringify} function stores the type `T` and its JSON string builder in the
* global memory and reused whenever the {@link stringify} function be called with the
* same type `T`.
*
* On the other hand, if you've encountered an error which starts from the
* "no transform has been configured" message when calling this {@link createStringifier}
* function, it means that you haven't configured the `tsconfig.json` file. Visit the
* https://github.com/samchon/typescript-json and configure the `tsconfig.json` file follow
* the [README](https://github.com/samchon/typescript-json#tsconfigjson) content.
*
* @return 2x faster `JSON.stringify()` function.
* @author Jeongho Nam - https://github.com/samchon
*/
export function createStringifier(): never;

/**
* 2x faster `JSON.stringify()` function generator.
*
Expand Down
16 changes: 11 additions & 5 deletions src/transformers/NodeTransformer.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import ts from "typescript";

import { FunctionFactory } from "../factories/FunctionFactory";
import { IProject } from "../structures/IProject";
import { get_json_function } from "../functional/get_json_function";

export namespace NodeTransformer
{
Expand All @@ -14,19 +14,25 @@ export namespace NodeTransformer
if (!ts.isCallExpression(expression))
return expression;

const func = get_json_function(project, expression);
const func: FunctionFactory.Closure | null = FunctionFactory.generate
(
project,
expression
);
if (func === null)
return expression;

const generic: ts.TypeNode = expression.typeArguments![0]!;
const type: ts.Type = project.checker.getTypeFromTypeNode(generic);
const noe: ts.TypeNode | null = (expression.typeArguments || [])[0] || null;
const type: ts.Type | null = noe
? project.checker.getTypeFromTypeNode(noe)
: null;

return ts.factory.updateCallExpression
(
expression,
expression.expression,
expression.typeArguments,
[ ...expression.arguments, func(project, type, generic) ]
[ ...expression.arguments, func(project, expression, type) ]
);
}
}
18 changes: 18 additions & 0 deletions test/features/test_stringify_atomic_implicit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import TSON from "../../src";

export function test_stringify_atomic_implicit(): void
{
test(input => TSON.stringify(input), true);
test(input => TSON.stringify(input), 3);
test(input => TSON.stringify(input), "hello");
test(input => TSON.stringify(input), null);
}

function test<T>(stringify: (input: T) => string, input: T)
{
const json: string = stringify(input);
const expected: string = JSON.stringify(input);

if (json !== expected)
throw new Error("Bug on TSON.stringify(): failed to understand the implicit atomic type.");
}
2 changes: 1 addition & 1 deletion test/features/test_stringify_class_closure.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import TSON from "../../src";

export function test_stringify_class_closure()
export function test_stringify_class_closure(): void
{
const something: Something = new Something("1234");
const json: string = TSON.stringify<Something>(something);
Expand Down
Loading

0 comments on commit 7740415

Please sign in to comment.