Skip to content

Commit

Permalink
Merge pull request #225 from samchon/v3.3
Browse files Browse the repository at this point in the history
Close #222 - `TSON.stringify()` supports dynamic properties
  • Loading branch information
samchon authored Oct 4, 2022
2 parents a93fed5 + 9b7d6b5 commit 4c47197
Show file tree
Hide file tree
Showing 13 changed files with 330 additions and 115 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": "3.3.4",
"version": "3.3.6",
"description": "Runtime type checkers and 5x faster JSON.stringify() function",
"main": "lib/index.js",
"typings": "lib/index.d.ts",
Expand Down
1 change: 0 additions & 1 deletion src/factories/internal/emplace_metadata_object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,6 @@ export const emplace_metadata_object =
: undefined,
(doc) => doc.name !== "default",
);
Writable(value).required = false;
}

return obj;
Expand Down
1 change: 0 additions & 1 deletion src/programmers/FeatureProgrammer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,6 @@ export namespace FeatureProgrammer {
return function (obj: MetadataObject) {
const entries: IExpressionEntry[] = [];

// REGULAR PROPERTY
for (const prop of obj.properties) {
const key: string | null = prop.key.getSoleLiteral();
const input: ts.Expression =
Expand Down
145 changes: 41 additions & 104 deletions src/programmers/helpers/StringifyJoinder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@ import ts from "typescript";

import { IdentifierFactory } from "../../factories/IdentifierFactory";
import { TemplateFactory } from "../../factories/TemplateFactory";
import { ValueFactory } from "../../factories/ValueFactory";

import { Metadata } from "../../metadata/Metadata";

import { stringify_dynamic_properties } from "../internal/stringify_dynamic_properties";
import { stringify_regular_properties } from "../internal/stringify_regular_properties";
import { FunctionImporter } from "./FunctionImporeter";
import { IExpressionEntry } from "./IExpressionEntry";

Expand All @@ -17,97 +16,45 @@ export namespace StringifyJoiner {
const regular: IExpressionEntry[] = entries.filter((entry) =>
entry.key.isSoleLiteral(),
);
if (regular.length === 0)
const dynamic: IExpressionEntry[] = entries.filter(
(entry) => !entry.key.isSoleLiteral(),
);
if (regular.length === 0 && dynamic.length === 0)
return ts.factory.createStringLiteral("{}");
regular.sort((x, y) => sequence(x.meta) - sequence(y.meta));

// GATHER PROPERTY EXNRESSIONS
const expressions: ts.Expression[] = [];
regular.forEach((entry, index) => {
const key: string | null = entry.key.getSoleLiteral();
if (key === null) return;

// BASE ELEMENTS
const base: ts.Expression[] = [
ts.factory.createStringLiteral(`${JSON.stringify(key)}:`),
entry.expression,
];
if (index !== regular.length - 1 /* || recursive !== null*/)
base.push(
ts.factory.createStringLiteral(
`,${" ".repeat(SPACES)}`,
),
);

const empty: boolean =
(entry.meta.required === false &&
entry.meta.nullable === false &&
entry.meta.size() === 0) ||
(entry.meta.functional &&
entry.meta.nullable === false &&
entry.meta.size() === 1);
// PROPERTIES
const expressions: ts.Expression[] = [
...stringify_regular_properties(regular, dynamic),
...(dynamic.length
? [
stringify_dynamic_properties(
dynamic,
regular.map((r) => r.key.getSoleLiteral()!),
),
]
: []),
];

if (empty === true)
expressions.push(ts.factory.createStringLiteral(""));
else if (
entry.meta.required === false ||
entry.meta.functional === true ||
entry.meta.any === true
)
expressions.push(
ts.factory.createConditionalExpression(
(() => {
const conditions: ts.BinaryExpression[] = [];
if (
entry.meta.required === false ||
entry.meta.any
)
conditions.push(
ts.factory.createStrictEquality(
ts.factory.createIdentifier(
"undefined",
),
entry.input,
),
);
if (entry.meta.functional || entry.meta.any)
conditions.push(
ts.factory.createStrictEquality(
ts.factory.createStringLiteral(
"function",
),
ValueFactory.TYPEOF(entry.input),
),
);
return conditions.length === 1
? conditions[0]!
: conditions.reduce((x, y) =>
ts.factory.createLogicalOr(x, y),
);
})(),
undefined,
ts.factory.createStringLiteral(""),
undefined,
TemplateFactory.generate(base),
),
);
else expressions.push(...base);
});
// POP LAST COMMA, IF REQUIRED
const filtered: ts.Expression[] =
(regular.length &&
regular[regular.length - 1]!.meta.required &&
dynamic.length === 0) ||
(regular.length === 0 && dynamic.length)
? expressions
: [
ts.factory.createCallExpression(
importer.use("tail"),
undefined,
[TemplateFactory.generate(expressions)],
),
];

const last: IExpressionEntry = regular[regular.length - 1]!;
const filtered: ts.Expression[] = last.meta.required
? expressions
: [
ts.factory.createCallExpression(
importer.use("tail"),
undefined,
[TemplateFactory.generate(expressions)],
),
];
// RETURNS WITH OBJECT BRACKET
return TemplateFactory.generate([
ts.factory.createStringLiteral(`{${" ".repeat(SPACES)}`),
ts.factory.createStringLiteral(`{`),
...filtered,
ts.factory.createStringLiteral(`${" ".repeat(SPACES)}}`),
ts.factory.createStringLiteral(`}`),
]);
};

Expand All @@ -116,7 +63,7 @@ export namespace StringifyJoiner {
arrow: ts.ArrowFunction,
): ts.Expression {
return TemplateFactory.generate([
ts.factory.createStringLiteral(`[${" ".repeat(SPACES)}`),
ts.factory.createStringLiteral(`[`),
ts.factory.createCallExpression(
ts.factory.createPropertyAccessExpression(
ts.factory.createCallExpression(
Expand All @@ -127,9 +74,9 @@ export namespace StringifyJoiner {
ts.factory.createIdentifier("join"),
),
undefined,
[ts.factory.createStringLiteral(`,${" ".repeat(SPACES)}`)],
[ts.factory.createStringLiteral(`,`)],
),
ts.factory.createStringLiteral(`${" ".repeat(SPACES)}]`),
ts.factory.createStringLiteral(`]`),
]);
}

Expand All @@ -144,23 +91,13 @@ export namespace StringifyJoiner {
"]",
);

const elements: ts.Expression[] = [
ts.factory.createStringLiteral(`[${" ".repeat(SPACES)}`),
];
const elements: ts.Expression[] = [ts.factory.createStringLiteral(`[`)];
children.forEach((child, i) => {
elements.push(child);
if (i !== children.length - 1)
elements.push(
ts.factory.createStringLiteral(`,${" ".repeat(SPACES)}`),
);
elements.push(ts.factory.createStringLiteral(`,`));
});
elements.push(ts.factory.createStringLiteral(`${" ".repeat(SPACES)}]`));
elements.push(ts.factory.createStringLiteral(`]`));
return TemplateFactory.generate(elements);
}
}

function sequence(meta: Metadata): number {
return meta.any || !meta.required || meta.functional ? 0 : 1;
}

const SPACES = 0;
20 changes: 13 additions & 7 deletions src/programmers/internal/check_dynamic_properties.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,25 @@ const check_dynamic_property =
// IF CONDITIONS
//----
// PREPARE ASSETS
const statements: ts.IfStatement[] = [];
const key = ts.factory.createIdentifier("key");
const value = ts.factory.createIdentifier("value");

const statements: ts.IfStatement[] = [
ts.factory.createIfStatement(
ts.factory.createStrictEquality(
ts.factory.createIdentifier("undefined"),
value,
),
ts.factory.createReturnStatement(ts.factory.createTrue()),
),
];
const add = (exp: ts.Expression, output: ts.Expression) =>
statements.push(
ts.factory.createIfStatement(
exp,
ts.factory.createReturnStatement(output),
),
);
const key = ts.factory.createIdentifier("key");
const value = ts.factory.createIdentifier("value");

// GATHER CONDITIONS
if (equals === true)
Expand Down Expand Up @@ -80,10 +89,7 @@ const check_dynamic_property =
...statements,
ts.factory.createReturnStatement(
equals === true
? ts.factory.createStrictEquality(
ts.factory.createIdentifier("undefined"),
value,
)
? ts.factory.createFalse()
: ts.factory.createTrue(),
),
],
Expand Down
Loading

0 comments on commit 4c47197

Please sign in to comment.