Skip to content

Commit

Permalink
t pMerge branch 'v3.3'
Browse files Browse the repository at this point in the history
  • Loading branch information
samchon committed Oct 3, 2022
2 parents 1b51534 + 780872b commit 67d50e5
Show file tree
Hide file tree
Showing 66 changed files with 1,280 additions and 248 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -204,13 +204,14 @@ Also, only `typescript-json` can validate union typed structure exactly. All the
Components | `TSON` | `T.IS` | `ajv` | `io-ts` | `C.V.`
-------------------------|-------------------|-----------------|-------|---------|------------------
**Easy to use** | ✔ | ✔ | ❌ | ❌ | ❌
[Additional Tags](https://github.com/samchon/typescript-json/#comment-tags) | ✔ | ❌ | ✔ | ✔ | ✔
[Template Literal Types](https://github.com/samchon/typescript-json/blob/master/test/structures/TemplateUnion.ts) | ✅ | ❌ | ❌ | ❌ | ❌
[Object (simple)](https://github.com/samchon/typescript-json/blob/master/test/structures/ObjectSimple.ts) | ✔ | ✔ | ✔ | ✔ | ✔
[Object (hierarchical)](https://github.com/samchon/typescript-json/blob/master/test/structures/ObjectHierarchical.ts) | ✔ | ✔ | ❌ | ✔ | ✔
[Object (recursive)](https://github.com/samchon/typescript-json/blob/master/test/structures/ObjectRecursive.ts) | ✔ | ✔ | ✔ | ✔ | ✔
[Object (union, implicit)](https://github.com/samchon/typescript-json/blob/master/test/structures/ObjectUnionImplicit.ts) | ✅ | ❌ | ❌ | ❌ | ❌
[Object (union, explicit)](https://github.com/samchon/typescript-json/blob/master/test/structures/ObjectUnionExplicit.ts) | ✔ | ❌ | ✔ | ✔ | ❌
[Object (additional tags)](https://github.com/samchon/typescript-json/#comment-tags) | ✔ | ❌ | ✔ | ✔ | ✔
[Object (template literal types)](https://github.com/samchon/typescript-json/blob/master/test/structures/TemplateUnion.ts) | ✅ | ❌ | ❌ | ❌ | ❌
[Object (dynamic properties)](https://github.com/samchon/typescript-json/blob/master/test/structures/DynamicTemplate.ts) | ✔ | ❌ | ✔ | ❌ | ❌
[Array (hierarchical)](https://github.com/samchon/typescript-json/blob/master/test/structures/ArrayHierarchical.ts) | ✔ | ✔ | ❌ | ✔ | ✔
[Array (recursive)](https://github.com/samchon/typescript-json/blob/master/test/structures/ArrayRecursive.ts) | ✔ | ✔ | ❌ | ✔ | ✔
[Array (recursive, union)](https://github.com/samchon/typescript-json/blob/master/test/structures/ArrayRecursiveUnionExplicit.ts) | ✔ | ✔ | ❌ | ❌ | ❌
Expand Down
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.2",
"version": "3.3.3",
"description": "Runtime type checkers and 5x faster JSON.stringify() function",
"main": "lib/index.js",
"typings": "lib/index.d.ts",
Expand Down
85 changes: 61 additions & 24 deletions src/factories/internal/emplace_metadata_object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,42 @@ export const emplace_metadata_object =
ts.isPropertySignature(node) ||
ts.isTypeLiteralNode(node);

const insert =
(key: Metadata) =>
(value: Metadata) =>
(identifier: () => string) =>
(
symbol: ts.Symbol | undefined,
filter?: (doc: ts.JSDocTagInfo) => boolean,
): MetadataProperty => {
// COMMENTS AND TAGS
const description: string | undefined =
CommentFactory.generate(
symbol?.getDocumentationComment(checker) || [],
) || undefined;
const jsDocTags: ts.JSDocTagInfo[] = (
symbol?.getJsDocTags() || []
).filter(filter || (() => true));

// THE PROPERTY
const property = MetadataProperty.create({
key,
value,
description,
jsDocTags,
tags: MetadataTagFactory.generate(
() => identifier(),
value,
jsDocTags,
),
});
obj.properties.push(property);
return property;
};

//----
// REGULAR PROPERTIES
//----
for (const prop of parent.getProperties()) {
// CHECK NODE IS A FORMAL PROPERTY
const node: ts.PropertyDeclaration | undefined =
Expand All @@ -56,35 +92,36 @@ export const emplace_metadata_object =
}

// GET EXACT TYPE
const key: string = prop.name;
const type: ts.Type = checker.getTypeOfSymbolAtLocation(prop, node);

// CHILD METADATA BY ADDITIONAL EXPLORATION
const child: Metadata = explore_metadata(checker)(options)(
const key: Metadata = MetadataHelper.literal_to_metadata(prop.name);
const value: Metadata = explore_metadata(checker)(options)(
collection,
)(type, false);
if (node.questionToken) Writable(child).required = false;

// ADD TO OBJECT PROPERTY
const property = MetadataProperty.create({
key: MetadataHelper.literal_to_metadata(key),
value: child,
description:
CommentFactory.generate(
prop.getDocumentationComment(checker),
) || undefined,
});
obj.properties.push(property);

// ASSIGN TAGS
property.tags.push(
...MetadataTagFactory.generate(
() => `${obj.name}.${key}`,
child,
prop.getJsDocTags(),
),
// INSERT WITH REQUIRED CONFIGURATION
if (node.questionToken) Writable(value).required = false;
insert(key)(value)(() => `${obj.name}.${prop.name}`)(prop);
}

//----
// DYNAMIC PROPERTIES
//----
for (const index of checker.getIndexInfosOfType(parent)) {
// GET EXACT TYPE
const analyzer = (type: ts.Type) =>
explore_metadata(checker)(options)(collection)(type, false);
const key: Metadata = analyzer(index.keyType);
const value: Metadata = analyzer(index.type);

// INSERT WITH REQUIRED CONFIGURATION
insert(key)(value)(() => `${obj.name}[${key.getName()}]`)(
index.declaration?.parent
? checker.getSymbolAtLocation(index.declaration.parent)
: undefined,
(doc) => doc.name !== "default",
);
property.jsDocTags.push(...prop.getJsDocTags());
Writable(value).required = false;
}

return obj;
};
7 changes: 7 additions & 0 deletions src/metadata/Metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,13 @@ export class Metadata {
return this.constants[0]!.values[0] as string;
else return null;
}

/**
* @internal
*/
public isSoleLiteral(): boolean {
return this.getSoleLiteral() !== null;
}
}
export namespace Metadata {
export function intersects(
Expand Down
17 changes: 7 additions & 10 deletions src/metadata/MetadataProperty.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,19 @@ export class MetadataProperty {
/**
* @hidden
*/
private constructor(
props: Omit<ClassProperties<MetadataProperty>, "tags" | "jsDocTags">,
) {
private constructor(props: ClassProperties<MetadataProperty>) {
this.key = props.key;
this.value = props.value;
this.description = props.description;
this.tags = [];
this.jsDocTags = [];
this.tags = props.tags;
this.jsDocTags = props.jsDocTags;
}

/**
* @internal
*/
public static create(
props: Omit<ClassProperties<MetadataProperty>, "tags" | "jsDocTags">,
props: ClassProperties<MetadataProperty>,
): MetadataProperty {
return new MetadataProperty(props);
}
Expand All @@ -45,14 +43,13 @@ export class MetadataProperty {
property: IMetadataProperty,
objects: Map<string, MetadataObject>,
) {
const obj = this.create({
return this.create({
key: Metadata._From(property.key, objects),
value: Metadata._From(property.value, objects),
description: property.description,
tags: property.tags.slice(),
jsDocTags: property.jsDocTags.slice(),
});
obj.tags.push(...property.tags.slice());
obj.jsDocTags.push(...property.jsDocTags.slice());
return obj;
}

public toJSON(): IMetadataProperty {
Expand Down
3 changes: 3 additions & 0 deletions src/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ export namespace assertType {
export const is_url = $is_url;
export const is_ipv4 = $is_ipv4;
export const is_ipv6 = $is_ipv6;
export const join = $join;

export function predicate(
matched: boolean,
Expand Down Expand Up @@ -227,6 +228,7 @@ export namespace validate {
export const is_url = $is_url;
export const is_ipv4 = $is_ipv4;
export const is_ipv6 = $is_ipv6;
export const join = $join;

export const predicate =
(res: IValidation) =>
Expand Down Expand Up @@ -408,6 +410,7 @@ export namespace equals {
export const is_url = $is_url;
export const is_ipv4 = $is_ipv4;
export const is_ipv6 = $is_ipv6;
export const join = $join;
}

/**
Expand Down
10 changes: 4 additions & 6 deletions src/programmers/AssertProgrammer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,7 @@ export namespace AssertProgrammer {
equals,
combiner: combine(equals)(importer),
joiner: CheckerProgrammer.DEFAULT_JOINER(
equals
? assert_object(importer)
: check_object(false)(true),
assert_object(equals)(importer),
),
},
modulo,
Expand All @@ -66,7 +64,7 @@ const combine =
(importer: FunctionImporter): CheckerProgrammer.IConfig.Combiner => {
return (explore: CheckerProgrammer.IExplore) => {
const combiner = IsProgrammer.CONFIG({
object: equals ? assert_object(importer) : undefined,
object: assert_object(equals)(importer),
numeric: true,
}).combiner;
if (explore.tracable === false && explore.from !== "top")
Expand Down Expand Up @@ -94,8 +92,8 @@ const combine =
};
};

const assert_object = (importer: FunctionImporter) =>
check_object(true)(true)((expr) =>
const assert_object = (equals: boolean) => (importer: FunctionImporter) =>
check_object(equals)(true)((expr) =>
ts.factory.createLogicalOr(
ts.factory.createStrictEquality(
ts.factory.createFalse(),
Expand Down
13 changes: 7 additions & 6 deletions src/programmers/CheckerProgrammer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,13 @@ export namespace CheckerProgrammer {
return FeatureProgrammer.generate(
project,
CONFIG(project, config, importer),
importer.empty() || addition
? () => [
...importer.declare(modulo),
...(addition ? addition() : []),
]
: undefined,
() =>
!importer.empty() || addition
? [
...importer.declare(modulo),
...(addition ? addition() : []),
]
: undefined,
);
}

Expand Down
40 changes: 23 additions & 17 deletions src/programmers/FeatureProgrammer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,9 @@ export namespace FeatureProgrammer {
(
project: IProject,
config: IConfig,
addition?: (collection: MetadataCollection) => ts.Statement[],
addition: (
collection: MetadataCollection,
) => ts.Statement[] | undefined,
) =>
(type: ts.Type) => {
const [collection, meta] = config.initializer(project, type);
Expand Down Expand Up @@ -103,7 +105,7 @@ export namespace FeatureProgrammer {
: generate_unioners(config)(collection);

// RETURNS THE OPTIMAL ARROW FUNCTION
const added: ts.Statement[] = addition ? addition(collection) : [];
const added: ts.Statement[] | undefined = addition(collection);

return ts.factory.createArrowFunction(
undefined,
Expand All @@ -113,7 +115,7 @@ export namespace FeatureProgrammer {
undefined,
ts.factory.createBlock(
[
...added,
...(added || []),
...(functors !== null
? [
ts.factory.createVariableStatement(
Expand Down Expand Up @@ -188,30 +190,34 @@ export namespace FeatureProgrammer {
// REGULAR PROPERTY
for (const prop of obj.properties) {
const key: string | null = prop.key.getSoleLiteral();
if (key === null) continue;

const access = Escaper.variable(key)
? ts.factory.createPropertyAccessExpression(
ValueFactory.INPUT(),
ts.factory.createIdentifier(key),
)
: ts.factory.createElementAccessExpression(
ValueFactory.INPUT(),
ts.factory.createStringLiteral(key),
);
const input: ts.Expression =
key === null
? ts.factory.createIdentifier("value")
: Escaper.variable(key)
? ts.factory.createPropertyAccessExpression(
ValueFactory.INPUT(),
ts.factory.createIdentifier(key),
)
: ts.factory.createElementAccessExpression(
ValueFactory.INPUT(),
ts.factory.createStringLiteral(key),
);

entries.push({
input: access,
input,
key: prop.key,
meta: prop.value,
expression: config.decoder(
access,
input,
prop.value,
{
tracable: config.trace,
source: "object",
from: "object",
postfix: IdentifierFactory.postfix(key),
postfix:
key !== null
? IdentifierFactory.postfix(key)
: `$join(key)`,
},
prop.tags,
),
Expand Down
16 changes: 3 additions & 13 deletions src/programmers/IsProgrammer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export namespace IsProgrammer {
: initial;
},
joiner: CheckerProgrammer.DEFAULT_JOINER(
options?.object || check_object(false)(true),
options?.object || check_object(false)(true)()(),
),
};
}
Expand All @@ -55,23 +55,13 @@ export namespace IsProgrammer {
equals: boolean = false,
) {
const importer: FunctionImporter = new FunctionImporter();
const object = equals
? check_object(equals)(true)((expr) =>
ts.factory.createLogicalOr(
ts.factory.createStrictEquality(
ts.factory.createFalse(),
ts.factory.createIdentifier("exceptionable"),
),
expr,
),
)()
: check_object(false)(true);
if (equals === true) importer.use("join");

return CheckerProgrammer.generate(
project,
{
...CONFIG({
object,
object: check_object(equals)(true)()(),
numeric: true,
}),
trace: equals,
Expand Down
Loading

0 comments on commit 67d50e5

Please sign in to comment.