typia 13.3.0 → 14.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/internal/_createStandardSchema.d.ts +1 -2
- package/lib/internal/_createStandardSchema.js.map +1 -1
- package/lib/internal/_createStandardSchema.mjs.map +1 -1
- package/lib/internal/_randomPattern.js +20 -3
- package/lib/internal/_randomPattern.js.map +1 -1
- package/lib/internal/_randomPattern.mjs +5 -1
- package/lib/internal/_randomPattern.mjs.map +1 -1
- package/lib/internal/_randomStringLength.js +9 -2
- package/lib/internal/_randomStringLength.js.map +1 -1
- package/lib/internal/_randomStringLength.mjs +3 -1
- package/lib/internal/_randomStringLength.mjs.map +1 -1
- package/lib/module.d.ts +1 -2
- package/lib/module.js.map +1 -1
- package/lib/module.mjs.map +1 -1
- package/lib/re-exports.d.ts +1 -1
- package/lib/re-exports.js.map +1 -1
- package/lib/transform.mjs +1 -1
- package/native/cmd/ttsc-typia/create_assert_error_factory_arity_test.go +5 -2
- package/native/cmd/ttsc-typia/dependency_collector_virtual_scheme_test.go +52 -0
- package/native/cmd/ttsc-typia/dynamic_key_tags_transform_test.go +206 -0
- package/native/cmd/ttsc-typia/notation_kebab_case_transform_test.go +2 -2
- package/native/cmd/ttsc-typia/project_catalog_transform_coverage_test.go +84 -85
- package/native/cmd/ttsc-typia/project_dependencies_callee_argument_transform_test.go +177 -0
- package/native/cmd/ttsc-typia/project_dependencies_callee_barrel_transform_test.go +115 -0
- package/native/cmd/ttsc-typia/project_dependencies_callee_inference_transform_test.go +285 -0
- package/native/cmd/ttsc-typia/project_dependencies_callee_shape_transform_test.go +117 -0
- package/native/cmd/ttsc-typia/project_dependencies_callee_untransformed_barrel_transform_test.go +121 -0
- package/native/cmd/ttsc-typia/project_dependencies_complete_diagnostic_transform_test.go +116 -0
- package/native/cmd/ttsc-typia/project_dependencies_complete_envelope_transform_test.go +115 -0
- package/native/cmd/ttsc-typia/project_dependencies_complete_inferred_type_transform_test.go +127 -0
- package/native/cmd/ttsc-typia/project_dependencies_complete_replaced_library_transform_test.go +153 -0
- package/native/cmd/ttsc-typia/project_dependencies_complete_untouched_reprint_transform_test.go +155 -0
- package/native/cmd/ttsc-typia/project_dependencies_computed_key_transform_test.go +218 -0
- package/native/cmd/ttsc-typia/project_dependencies_custom_lib_name_transform_test.go +6 -5
- package/native/cmd/ttsc-typia/project_dependencies_enum_member_value_transform_test.go +131 -0
- package/native/cmd/ttsc-typia/project_dependencies_inferred_declaration_transform_test.go +159 -0
- package/native/cmd/ttsc-typia/project_dependencies_jsdoc_typedef_transform_test.go +134 -0
- package/native/cmd/ttsc-typia/project_dependencies_named_tuple_member_transform_test.go +123 -0
- package/native/cmd/ttsc-typia/project_dependencies_qualified_barrel_transform_test.go +141 -0
- package/native/cmd/ttsc-typia/project_dependencies_type_parameter_default_transform_test.go +127 -0
- package/native/cmd/ttsc-typia/template_literal_type_tags_transform_test.go +3 -1
- package/native/cmd/ttsc-typia/transform.go +195 -21
- package/native/cmd/ttsc-typia/transform_helpers_test.go +12 -0
- package/native/core/factories/MetadataCommentTagFactory.go +96 -27
- package/native/core/factories/metadata_comment_tag_factory_coverage_test.go +2 -2
- package/native/core/factories/metadata_comment_tag_factory_rejects_out_of_range_integer_test.go +124 -0
- package/native/core/programmers/AssertProgrammer.go +20 -6
- package/native/core/programmers/RandomProgrammer.go +78 -6
- package/native/core/programmers/ValidateProgrammer.go +21 -6
- package/native/core/programmers/helpers/RandomJoiner.go +8 -1
- package/native/core/programmers/iterate/check_dynamic_properties.go +177 -3
- package/native/core/programmers/iterate/check_object.go +12 -1
- package/native/core/schemas/metadata/MetadataDependency.go +613 -30
- package/native/transform/CallExpressionTransformer.go +16 -1
- package/package.json +4 -14
- package/src/internal/_createStandardSchema.ts +1 -2
- package/src/internal/_randomPattern.ts +18 -3
- package/src/internal/_randomStringLength.ts +9 -2
- package/src/module.ts +6 -2
- package/src/re-exports.ts +13 -0
- package/lib/executable/FileSystemIdentity.d.ts +0 -44
- package/lib/executable/FileSystemIdentity.js +0 -213
- package/lib/executable/FileSystemIdentity.js.map +0 -1
- package/lib/executable/FileSystemIdentity.mjs +0 -133
- package/lib/executable/FileSystemIdentity.mjs.map +0 -1
- package/lib/executable/TypiaGenerateWizard.d.ts +0 -9
- package/lib/executable/TypiaGenerateWizard.js +0 -852
- package/lib/executable/TypiaGenerateWizard.js.map +0 -1
- package/lib/executable/TypiaGenerateWizard.mjs +0 -618
- package/lib/executable/TypiaGenerateWizard.mjs.map +0 -1
- package/lib/executable/generate/ttsc.d.ts +0 -1
- package/lib/executable/generate/ttsc.js +0 -53
- package/lib/executable/generate/ttsc.js.map +0 -1
- package/lib/executable/generate/ttsc.mjs +0 -37
- package/lib/executable/generate/ttsc.mjs.map +0 -1
- package/lib/executable/typia.d.ts +0 -2
- package/lib/executable/typia.js +0 -84
- package/lib/executable/typia.js.map +0 -1
- package/lib/executable/typia.mjs +0 -60
- package/lib/executable/typia.mjs.map +0 -1
- package/src/executable/FileSystemIdentity.ts +0 -222
- package/src/executable/TypiaGenerateWizard.ts +0 -1133
- package/src/executable/generate/ttsc.ts +0 -70
- package/src/executable/typia.ts +0 -80
|
@@ -48,6 +48,13 @@ func (callExpressionTransformerNamespace) Transform(props CallExpressionTransfor
|
|
|
48
48
|
if props.Expression == nil {
|
|
49
49
|
return nil
|
|
50
50
|
}
|
|
51
|
+
// Report what SELECTS this callee before asking what it resolved to (project
|
|
52
|
+
// transform mode only; a no-op otherwise). Typia-ness is decided by the file
|
|
53
|
+
// that declares the resolved signature, so the modules an import or re-export
|
|
54
|
+
// chain traverses decide whether this call is rewritten -- and the report has
|
|
55
|
+
// to happen for a rejected call too, because that is the one an edit to one
|
|
56
|
+
// of those modules turns into a generated validator.
|
|
57
|
+
schemametadata.MetadataDependency_touchCallee(props.Context.Checker, props.Expression.Expression)
|
|
51
58
|
signature := props.Context.Checker.GetResolvedSignature(props.Expression.AsNode())
|
|
52
59
|
if signature == nil {
|
|
53
60
|
return props.Expression.AsNode()
|
|
@@ -94,10 +101,18 @@ func (callExpressionTransformerNamespace) TransformKnown(props CallExpressionTra
|
|
|
94
101
|
// intrinsic (`typia.validate<Id>()` with `type Id = string` elsewhere) leaves
|
|
95
102
|
// no symbol on the resolved type, so the call site's own syntax is the only
|
|
96
103
|
// anchor that registers such an alias' declaring file.
|
|
97
|
-
|
|
104
|
+
//
|
|
105
|
+
// A call that writes no type argument takes its validated type from the value
|
|
106
|
+
// argument instead, and no walk bounds where that type was decided: contextual
|
|
107
|
+
// typing can put the deciding annotation in a file the resolved type never
|
|
108
|
+
// names. Report it as unbounded, which costs the file its completeness
|
|
109
|
+
// declaration rather than vouching for a list that cannot cover it.
|
|
110
|
+
if props.Expression.TypeArguments != nil && len(props.Expression.TypeArguments.Nodes) != 0 {
|
|
98
111
|
for _, argument := range props.Expression.TypeArguments.Nodes {
|
|
99
112
|
schemametadata.MetadataDependency_touchTypeNode(props.Context.Checker, argument)
|
|
100
113
|
}
|
|
114
|
+
} else {
|
|
115
|
+
schemametadata.MetadataDependency_unbounded(props.Context.Checker)
|
|
101
116
|
}
|
|
102
117
|
// Keep the full callee expression (e.g. `typia.assertEquals`) as the modulo,
|
|
103
118
|
// mirroring the TypeScript transformer. Programmers render it into the
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "typia",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "14.0.1",
|
|
4
4
|
"description": "Superfast runtime validators with only one line",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -26,9 +26,6 @@
|
|
|
26
26
|
},
|
|
27
27
|
"./package.json": "./package.json"
|
|
28
28
|
},
|
|
29
|
-
"bin": {
|
|
30
|
-
"typia": "./lib/executable/typia.js"
|
|
31
|
-
},
|
|
32
29
|
"ttsc": {
|
|
33
30
|
"plugin": {
|
|
34
31
|
"transform": "typia/lib/transform"
|
|
@@ -45,13 +42,9 @@
|
|
|
45
42
|
},
|
|
46
43
|
"homepage": "https://typia.io",
|
|
47
44
|
"dependencies": {
|
|
48
|
-
"@standard-schema/spec": "^1.0.0",
|
|
49
|
-
"commander": "^10.0.0",
|
|
50
|
-
"inquirer": "^8.2.5",
|
|
51
45
|
"randexp": "^0.5.3",
|
|
52
|
-
"
|
|
53
|
-
"@typia/
|
|
54
|
-
"@typia/utils": "^13.3.0"
|
|
46
|
+
"@typia/interface": "^14.0.1",
|
|
47
|
+
"@typia/utils": "^14.0.1"
|
|
55
48
|
},
|
|
56
49
|
"peerDependencies": {
|
|
57
50
|
"ttsc": ">=0.19.2"
|
|
@@ -62,13 +55,10 @@
|
|
|
62
55
|
}
|
|
63
56
|
},
|
|
64
57
|
"devDependencies": {
|
|
65
|
-
"@types/inquirer": "^8.2.5",
|
|
66
58
|
"@types/node": "^25.3.0",
|
|
67
|
-
"chalk": "^4.0.0",
|
|
68
59
|
"rimraf": "^6.1.2",
|
|
69
60
|
"rolldown": "^1.1.5",
|
|
70
|
-
"
|
|
71
|
-
"ttsc": "^0.19.2",
|
|
61
|
+
"ttsc": "^0.28.1",
|
|
72
62
|
"typescript": "^7.0.2"
|
|
73
63
|
},
|
|
74
64
|
"sideEffects": false,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import RandExp from "randexp";
|
|
2
2
|
|
|
3
3
|
import { _ILengthProps } from "./_randomStringLength";
|
|
4
|
+
import { _stringLength } from "./_stringLength";
|
|
4
5
|
|
|
5
6
|
export const _randomPattern = (
|
|
6
7
|
regex: RegExp,
|
|
@@ -16,14 +17,28 @@ export const _randomPattern = (
|
|
|
16
17
|
if (max !== undefined) r.max = max;
|
|
17
18
|
else if (min !== undefined && min * 2 > r.max) r.max = min * 2;
|
|
18
19
|
|
|
20
|
+
// The verification counts characters, not UTF-16 code units, because that is
|
|
21
|
+
// what `MinLength` and `MaxLength` compare against. `Pattern` compiles to a
|
|
22
|
+
// flagless `RegExp`, so a quantifier binds one code unit wherever its atom is
|
|
23
|
+
// a bare astral character: under `^😀+$` the `+` repeats the trailing low
|
|
24
|
+
// surrogate alone, and RandExp draws `\ud83d` + k * `\ude00` -- k characters
|
|
25
|
+
// in k + 1 code units. Measuring in code units accepted a two-character draw
|
|
26
|
+
// for `MinLength<3>` and handed back a value the generated validator rejects.
|
|
27
|
+
// Group the atom (`^(?:😀)+$`) and the arithmetic changes to 2k units for k
|
|
28
|
+
// characters; the two counts still differ, which is the point.
|
|
29
|
+
//
|
|
30
|
+
// The count is taken only after the pattern matches, and only when a bound
|
|
31
|
+
// exists, so an unbounded draw still walks nothing.
|
|
19
32
|
const bounded: boolean = min !== undefined || max !== undefined;
|
|
20
33
|
const limit: number = bounded ? 1024 : 10;
|
|
21
34
|
for (let i: number = 0; i < limit; ++i) {
|
|
22
35
|
const str: string = r.gen();
|
|
36
|
+
if (regex.test(str) === false) continue;
|
|
37
|
+
if (bounded === false) return str;
|
|
38
|
+
const length: number = _stringLength(str);
|
|
23
39
|
if (
|
|
24
|
-
|
|
25
|
-
(
|
|
26
|
-
(max === undefined || str.length <= max)
|
|
40
|
+
(min === undefined || length >= min) &&
|
|
41
|
+
(max === undefined || length <= max)
|
|
27
42
|
)
|
|
28
43
|
return str;
|
|
29
44
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { _randomInteger } from "./_randomInteger";
|
|
2
2
|
import { _randomString } from "./_randomString";
|
|
3
|
+
import { _stringLength } from "./_stringLength";
|
|
3
4
|
|
|
4
5
|
export const _RANDOM_LENGTH_ERROR =
|
|
5
6
|
"unable to generate a random string satisfying both the format and the length constraints.";
|
|
@@ -106,9 +107,15 @@ export const _randomFormatLength = (
|
|
|
106
107
|
return generate();
|
|
107
108
|
for (let i: number = 0; i < 256; ++i) {
|
|
108
109
|
const value: string = generate();
|
|
110
|
+
// Characters, not UTF-16 code units: `minLength` and `maxLength` are the
|
|
111
|
+
// bounds the generated validator compares in characters. `uuid` and `date`,
|
|
112
|
+
// the only two shapes routed through here, are ASCII, so the two counts
|
|
113
|
+
// agree for them today -- this keeps one measure so a later non-ASCII
|
|
114
|
+
// format cannot reintroduce the divergence unnoticed.
|
|
115
|
+
const length: number = _stringLength(value);
|
|
109
116
|
if (
|
|
110
|
-
(props.minLength === undefined ||
|
|
111
|
-
(props.maxLength === undefined ||
|
|
117
|
+
(props.minLength === undefined || length >= props.minLength) &&
|
|
118
|
+
(props.maxLength === undefined || length <= props.maxLength)
|
|
112
119
|
)
|
|
113
120
|
return value;
|
|
114
121
|
}
|
package/src/module.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
IRandomGenerator,
|
|
3
|
+
IValidation,
|
|
4
|
+
Resolved,
|
|
5
|
+
StandardSchemaV1,
|
|
6
|
+
} from "@typia/interface";
|
|
3
7
|
|
|
4
8
|
import { TypeGuardError } from "./TypeGuardError";
|
|
5
9
|
import { NoTransformConfigurationError } from "./transformers/NoTransformConfigurationError";
|
package/src/re-exports.ts
CHANGED
|
@@ -1,11 +1,23 @@
|
|
|
1
|
+
// Every type a public `typia.*` signature exposes must be re-exported here.
|
|
2
|
+
//
|
|
3
|
+
// A consumer compiling with `declaration: true` may only name an inferred type
|
|
4
|
+
// through a module specifier it can resolve itself, and typia's dependencies
|
|
5
|
+
// are not among them under an isolated `node_modules` layout such as pnpm's:
|
|
6
|
+
// they sit beside typia, not above the consumer. Without the re-export that
|
|
7
|
+
// emit has nothing portable to write, so TypeScript reports TS2742 (TS2883
|
|
8
|
+
// since TypeScript 7); with it, the emit writes `typia.<Name>`.
|
|
9
|
+
//
|
|
10
|
+
// `experiments/declaration` is the guard. See samchon/typia#2359.
|
|
1
11
|
export type {
|
|
2
12
|
// validate
|
|
3
13
|
AssertionGuard,
|
|
4
14
|
IJsonParseResult,
|
|
5
15
|
IValidation,
|
|
6
16
|
IRandomGenerator,
|
|
17
|
+
StandardSchemaV1,
|
|
7
18
|
// json
|
|
8
19
|
OpenApi,
|
|
20
|
+
IJsonSchemaApplication,
|
|
9
21
|
IJsonSchemaCollection,
|
|
10
22
|
IJsonSchemaUnit,
|
|
11
23
|
// llm
|
|
@@ -22,6 +34,7 @@ export type {
|
|
|
22
34
|
IMetadataTypeTag,
|
|
23
35
|
IJsDocTagInfo,
|
|
24
36
|
// typings
|
|
37
|
+
Atomic,
|
|
25
38
|
Classifiable,
|
|
26
39
|
ClassifyResult,
|
|
27
40
|
Primitive,
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import fs from "fs";
|
|
2
|
-
import path from "path";
|
|
3
|
-
export declare namespace FileSystemIdentity {
|
|
4
|
-
interface IIdentity {
|
|
5
|
-
readonly caseSensitive: boolean;
|
|
6
|
-
contains(file: string, directory: string): boolean;
|
|
7
|
-
filesystemKey(file: string): string;
|
|
8
|
-
isDeclarationFile(file: string): boolean;
|
|
9
|
-
isSamePath(x: string, y: string): boolean;
|
|
10
|
-
isSupportedExtension(file: string): boolean;
|
|
11
|
-
projectFileKey(file: string): string;
|
|
12
|
-
}
|
|
13
|
-
function create(caseSensitive: boolean, pathApi?: typeof path.posix): IIdentity;
|
|
14
|
-
class Policy {
|
|
15
|
-
private caseSensitive_;
|
|
16
|
-
private location_;
|
|
17
|
-
observe(caseSensitive: boolean | undefined, location: string): void;
|
|
18
|
-
get(): IIdentity;
|
|
19
|
-
}
|
|
20
|
-
function inspectDirectory(directory: string): Promise<boolean | undefined>;
|
|
21
|
-
function probeDirectory(directory: string): Promise<boolean>;
|
|
22
|
-
/**
|
|
23
|
-
* Builds the key that decides whether two paths are the same filesystem
|
|
24
|
-
* object.
|
|
25
|
-
*
|
|
26
|
-
* The identity is read from `fs.BigIntStats` rather than `fs.Stats`, because
|
|
27
|
-
* `fs.Stats.ino` is a JavaScript number. An NTFS file ID is `(sequenceNumber
|
|
28
|
-
* << 48) | mftRecordIndex` and routinely exceeds `Number.MAX_SAFE_INTEGER` —
|
|
29
|
-
* in a 4000-directory probe, 1879 of them did — where the spacing between
|
|
30
|
-
* representable doubles is 8 or more. Two entries sharing a sequence number
|
|
31
|
-
* with MFT record indices within that spacing round to one double. The
|
|
32
|
-
* traversal callers would then treat a distinct directory or file as already
|
|
33
|
-
* visited and skip it with no diagnostic, and the overwrite guard would
|
|
34
|
-
* refuse a legitimate output (samchon/typia#2269).
|
|
35
|
-
*
|
|
36
|
-
* A filesystem that reports no inode at all keeps the canonical path
|
|
37
|
-
* fallback, which is the only identity available there.
|
|
38
|
-
*
|
|
39
|
-
* @param stat Stats read with `{ bigint: true }`.
|
|
40
|
-
* @param realpath Canonical path of the same object.
|
|
41
|
-
* @returns Key that is equal for two paths only when they are one object.
|
|
42
|
-
*/
|
|
43
|
-
function identityKey(stat: Pick<fs.BigIntStats, "dev" | "ino">, realpath: string): string;
|
|
44
|
-
}
|
|
@@ -1,213 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
-
};
|
|
14
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.FileSystemIdentity = void 0;
|
|
16
|
-
const fs_1 = __importDefault(require("fs"));
|
|
17
|
-
const path_1 = __importDefault(require("path"));
|
|
18
|
-
var FileSystemIdentity;
|
|
19
|
-
(function (FileSystemIdentity) {
|
|
20
|
-
function create(caseSensitive, pathApi = path_1.default) {
|
|
21
|
-
const fold = (value) => caseSensitive ? value : value.toLowerCase();
|
|
22
|
-
const filesystemKey = (file) => fold(pathApi.normalize(file));
|
|
23
|
-
return {
|
|
24
|
-
caseSensitive,
|
|
25
|
-
contains: (file, directory) => {
|
|
26
|
-
const fileKey = filesystemKey(pathApi.resolve(file));
|
|
27
|
-
const directoryKey = filesystemKey(pathApi.resolve(directory));
|
|
28
|
-
const prefix = directoryKey.endsWith(pathApi.sep)
|
|
29
|
-
? directoryKey
|
|
30
|
-
: `${directoryKey}${pathApi.sep}`;
|
|
31
|
-
return fileKey === directoryKey || fileKey.startsWith(prefix);
|
|
32
|
-
},
|
|
33
|
-
filesystemKey,
|
|
34
|
-
isDeclarationFile: (file) => DTS_PATTERN.test(fold(pathApi.basename(file))),
|
|
35
|
-
isSamePath: (x, y) => filesystemKey(x) === filesystemKey(y),
|
|
36
|
-
isSupportedExtension: (file) => {
|
|
37
|
-
const filename = fold(pathApi.basename(file));
|
|
38
|
-
return (TS_PATTERN.test(filename) && DTS_PATTERN.test(filename) === false);
|
|
39
|
-
},
|
|
40
|
-
projectFileKey: fold,
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
FileSystemIdentity.create = create;
|
|
44
|
-
class Policy {
|
|
45
|
-
observe(caseSensitive, location) {
|
|
46
|
-
if (caseSensitive === undefined)
|
|
47
|
-
return;
|
|
48
|
-
if (this.caseSensitive_ === undefined) {
|
|
49
|
-
this.caseSensitive_ = caseSensitive;
|
|
50
|
-
this.location_ = location;
|
|
51
|
-
}
|
|
52
|
-
else if (this.caseSensitive_ !== caseSensitive) {
|
|
53
|
-
throw new URIError(`Error on TypiaGenerateWizard.generate(): inconsistent filesystem case behavior between ${this.location_} and ${location}.`);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
get() {
|
|
57
|
-
if (this.caseSensitive_ === undefined) {
|
|
58
|
-
throw new URIError("Error on TypiaGenerateWizard.generate(): unable to determine filesystem case behavior for this run.");
|
|
59
|
-
}
|
|
60
|
-
return create(this.caseSensitive_);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
FileSystemIdentity.Policy = Policy;
|
|
64
|
-
function inspectDirectory(directory) {
|
|
65
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
66
|
-
const names = yield fs_1.default.promises.readdir(directory);
|
|
67
|
-
const entries = new Set(names);
|
|
68
|
-
for (const name of names) {
|
|
69
|
-
const alternate = alternateCase(name);
|
|
70
|
-
if (alternate === undefined)
|
|
71
|
-
continue;
|
|
72
|
-
if (entries.has(alternate))
|
|
73
|
-
return true;
|
|
74
|
-
try {
|
|
75
|
-
yield fs_1.default.promises.lstat(path_1.default.join(directory, alternate));
|
|
76
|
-
return false;
|
|
77
|
-
}
|
|
78
|
-
catch (error) {
|
|
79
|
-
if (isMissingFileError(error))
|
|
80
|
-
return true;
|
|
81
|
-
throw error;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
return undefined;
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
|
-
FileSystemIdentity.inspectDirectory = inspectDirectory;
|
|
88
|
-
function probeDirectory(directory) {
|
|
89
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
90
|
-
const inspected = yield inspectDirectory(directory);
|
|
91
|
-
if (inspected !== undefined)
|
|
92
|
-
return inspected;
|
|
93
|
-
for (let attempt = 0; attempt < 10; ++attempt) {
|
|
94
|
-
const name = `.typia-case-probe-${process.pid}-${Date.now()}-${Math.random()
|
|
95
|
-
.toString(36)
|
|
96
|
-
.slice(2)}`.toLowerCase();
|
|
97
|
-
const original = path_1.default.join(directory, name);
|
|
98
|
-
const alternate = path_1.default.join(directory, name.toUpperCase());
|
|
99
|
-
let handle;
|
|
100
|
-
try {
|
|
101
|
-
handle = yield fs_1.default.promises.open(original, "wx");
|
|
102
|
-
}
|
|
103
|
-
catch (error) {
|
|
104
|
-
if (isAlreadyExistsError(error))
|
|
105
|
-
continue;
|
|
106
|
-
throw new URIError(`Error on TypiaGenerateWizard.generate(): unable to probe filesystem case behavior at ${directory}: ${formatUnknownError(error)}`);
|
|
107
|
-
}
|
|
108
|
-
let closed = false;
|
|
109
|
-
try {
|
|
110
|
-
yield handle.close();
|
|
111
|
-
closed = true;
|
|
112
|
-
try {
|
|
113
|
-
yield fs_1.default.promises.lstat(alternate);
|
|
114
|
-
return false;
|
|
115
|
-
}
|
|
116
|
-
catch (error) {
|
|
117
|
-
if (isMissingFileError(error))
|
|
118
|
-
return true;
|
|
119
|
-
throw error;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
finally {
|
|
123
|
-
let cleanupError;
|
|
124
|
-
if (closed === false) {
|
|
125
|
-
try {
|
|
126
|
-
yield handle.close();
|
|
127
|
-
}
|
|
128
|
-
catch (error) {
|
|
129
|
-
cleanupError = error;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
try {
|
|
133
|
-
yield fs_1.default.promises.unlink(original);
|
|
134
|
-
}
|
|
135
|
-
catch (error) {
|
|
136
|
-
if (isMissingFileError(error) === false)
|
|
137
|
-
cleanupError !== null && cleanupError !== void 0 ? cleanupError : (cleanupError = error);
|
|
138
|
-
}
|
|
139
|
-
if (cleanupError !== undefined) {
|
|
140
|
-
throw new URIError(`Error on TypiaGenerateWizard.generate(): unable to clean filesystem case probe ${original}: ${formatUnknownError(cleanupError)}`);
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
throw new URIError(`Error on TypiaGenerateWizard.generate(): unable to reserve a filesystem case probe at ${directory}.`);
|
|
145
|
-
});
|
|
146
|
-
}
|
|
147
|
-
FileSystemIdentity.probeDirectory = probeDirectory;
|
|
148
|
-
/**
|
|
149
|
-
* Builds the key that decides whether two paths are the same filesystem
|
|
150
|
-
* object.
|
|
151
|
-
*
|
|
152
|
-
* The identity is read from `fs.BigIntStats` rather than `fs.Stats`, because
|
|
153
|
-
* `fs.Stats.ino` is a JavaScript number. An NTFS file ID is `(sequenceNumber
|
|
154
|
-
* << 48) | mftRecordIndex` and routinely exceeds `Number.MAX_SAFE_INTEGER` —
|
|
155
|
-
* in a 4000-directory probe, 1879 of them did — where the spacing between
|
|
156
|
-
* representable doubles is 8 or more. Two entries sharing a sequence number
|
|
157
|
-
* with MFT record indices within that spacing round to one double. The
|
|
158
|
-
* traversal callers would then treat a distinct directory or file as already
|
|
159
|
-
* visited and skip it with no diagnostic, and the overwrite guard would
|
|
160
|
-
* refuse a legitimate output (samchon/typia#2269).
|
|
161
|
-
*
|
|
162
|
-
* A filesystem that reports no inode at all keeps the canonical path
|
|
163
|
-
* fallback, which is the only identity available there.
|
|
164
|
-
*
|
|
165
|
-
* @param stat Stats read with `{ bigint: true }`.
|
|
166
|
-
* @param realpath Canonical path of the same object.
|
|
167
|
-
* @returns Key that is equal for two paths only when they are one object.
|
|
168
|
-
*/
|
|
169
|
-
function identityKey(stat, realpath) {
|
|
170
|
-
// `BigInt(0)` rather than `0n`: this package compiles at ES2016, where a
|
|
171
|
-
// BigInt literal is a syntax error, while the constructor and the `bigint`
|
|
172
|
-
// type are fine.
|
|
173
|
-
return stat.ino === BigInt(0)
|
|
174
|
-
? `path:${path_1.default.normalize(realpath)}`
|
|
175
|
-
: `inode:${stat.dev}:${stat.ino}`;
|
|
176
|
-
}
|
|
177
|
-
FileSystemIdentity.identityKey = identityKey;
|
|
178
|
-
function alternateCase(name) {
|
|
179
|
-
let changed = false;
|
|
180
|
-
let output = "";
|
|
181
|
-
for (const character of name) {
|
|
182
|
-
if (character >= "a" && character <= "z") {
|
|
183
|
-
output += character.toUpperCase();
|
|
184
|
-
changed = true;
|
|
185
|
-
}
|
|
186
|
-
else if (character >= "A" && character <= "Z") {
|
|
187
|
-
output += character.toLowerCase();
|
|
188
|
-
changed = true;
|
|
189
|
-
}
|
|
190
|
-
else
|
|
191
|
-
output += character;
|
|
192
|
-
}
|
|
193
|
-
return changed ? output : undefined;
|
|
194
|
-
}
|
|
195
|
-
function isAlreadyExistsError(error) {
|
|
196
|
-
return (typeof error === "object" &&
|
|
197
|
-
error !== null &&
|
|
198
|
-
"code" in error &&
|
|
199
|
-
error.code === "EEXIST");
|
|
200
|
-
}
|
|
201
|
-
function isMissingFileError(error) {
|
|
202
|
-
return (typeof error === "object" &&
|
|
203
|
-
error !== null &&
|
|
204
|
-
"code" in error &&
|
|
205
|
-
error.code === "ENOENT");
|
|
206
|
-
}
|
|
207
|
-
function formatUnknownError(error) {
|
|
208
|
-
return error instanceof Error ? error.message : String(error);
|
|
209
|
-
}
|
|
210
|
-
})(FileSystemIdentity || (exports.FileSystemIdentity = FileSystemIdentity = {}));
|
|
211
|
-
const TS_PATTERN = /\.[cm]?tsx?$/;
|
|
212
|
-
const DTS_PATTERN = /\.d\.[cm]?tsx?$/;
|
|
213
|
-
//# sourceMappingURL=FileSystemIdentity.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"FileSystemIdentity.js","sourceRoot":"","sources":["../../src/executable/FileSystemIdentity.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
import fs from "fs";
|
|
2
|
-
import path from "path";
|
|
3
|
-
//#region src/executable/FileSystemIdentity.ts
|
|
4
|
-
let FileSystemIdentity;
|
|
5
|
-
(function(_FileSystemIdentity) {
|
|
6
|
-
function create(caseSensitive, pathApi = path) {
|
|
7
|
-
const fold = (value) => caseSensitive ? value : value.toLowerCase();
|
|
8
|
-
const filesystemKey = (file) => fold(pathApi.normalize(file));
|
|
9
|
-
return {
|
|
10
|
-
caseSensitive,
|
|
11
|
-
contains: (file, directory) => {
|
|
12
|
-
const fileKey = filesystemKey(pathApi.resolve(file));
|
|
13
|
-
const directoryKey = filesystemKey(pathApi.resolve(directory));
|
|
14
|
-
const prefix = directoryKey.endsWith(pathApi.sep) ? directoryKey : `${directoryKey}${pathApi.sep}`;
|
|
15
|
-
return fileKey === directoryKey || fileKey.startsWith(prefix);
|
|
16
|
-
},
|
|
17
|
-
filesystemKey,
|
|
18
|
-
isDeclarationFile: (file) => DTS_PATTERN.test(fold(pathApi.basename(file))),
|
|
19
|
-
isSamePath: (x, y) => filesystemKey(x) === filesystemKey(y),
|
|
20
|
-
isSupportedExtension: (file) => {
|
|
21
|
-
const filename = fold(pathApi.basename(file));
|
|
22
|
-
return TS_PATTERN.test(filename) && DTS_PATTERN.test(filename) === false;
|
|
23
|
-
},
|
|
24
|
-
projectFileKey: fold
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
_FileSystemIdentity.create = create;
|
|
28
|
-
class Policy {
|
|
29
|
-
observe(caseSensitive, location) {
|
|
30
|
-
if (caseSensitive === void 0) return;
|
|
31
|
-
if (this.caseSensitive_ === void 0) {
|
|
32
|
-
this.caseSensitive_ = caseSensitive;
|
|
33
|
-
this.location_ = location;
|
|
34
|
-
} else if (this.caseSensitive_ !== caseSensitive) throw new URIError(`Error on TypiaGenerateWizard.generate(): inconsistent filesystem case behavior between ${this.location_} and ${location}.`);
|
|
35
|
-
}
|
|
36
|
-
get() {
|
|
37
|
-
if (this.caseSensitive_ === void 0) throw new URIError("Error on TypiaGenerateWizard.generate(): unable to determine filesystem case behavior for this run.");
|
|
38
|
-
return create(this.caseSensitive_);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
_FileSystemIdentity.Policy = Policy;
|
|
42
|
-
async function inspectDirectory(directory) {
|
|
43
|
-
const names = await fs.promises.readdir(directory);
|
|
44
|
-
const entries = new Set(names);
|
|
45
|
-
for (const name of names) {
|
|
46
|
-
const alternate = alternateCase(name);
|
|
47
|
-
if (alternate === void 0) continue;
|
|
48
|
-
if (entries.has(alternate)) return true;
|
|
49
|
-
try {
|
|
50
|
-
await fs.promises.lstat(path.join(directory, alternate));
|
|
51
|
-
return false;
|
|
52
|
-
} catch (error) {
|
|
53
|
-
if (isMissingFileError(error)) return true;
|
|
54
|
-
throw error;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
_FileSystemIdentity.inspectDirectory = inspectDirectory;
|
|
59
|
-
async function probeDirectory(directory) {
|
|
60
|
-
const inspected = await inspectDirectory(directory);
|
|
61
|
-
if (inspected !== void 0) return inspected;
|
|
62
|
-
for (let attempt = 0; attempt < 10; ++attempt) {
|
|
63
|
-
const name = `.typia-case-probe-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`.toLowerCase();
|
|
64
|
-
const original = path.join(directory, name);
|
|
65
|
-
const alternate = path.join(directory, name.toUpperCase());
|
|
66
|
-
let handle;
|
|
67
|
-
try {
|
|
68
|
-
handle = await fs.promises.open(original, "wx");
|
|
69
|
-
} catch (error) {
|
|
70
|
-
if (isAlreadyExistsError(error)) continue;
|
|
71
|
-
throw new URIError(`Error on TypiaGenerateWizard.generate(): unable to probe filesystem case behavior at ${directory}: ${formatUnknownError(error)}`);
|
|
72
|
-
}
|
|
73
|
-
let closed = false;
|
|
74
|
-
try {
|
|
75
|
-
await handle.close();
|
|
76
|
-
closed = true;
|
|
77
|
-
try {
|
|
78
|
-
await fs.promises.lstat(alternate);
|
|
79
|
-
return false;
|
|
80
|
-
} catch (error) {
|
|
81
|
-
if (isMissingFileError(error)) return true;
|
|
82
|
-
throw error;
|
|
83
|
-
}
|
|
84
|
-
} finally {
|
|
85
|
-
let cleanupError;
|
|
86
|
-
if (closed === false) try {
|
|
87
|
-
await handle.close();
|
|
88
|
-
} catch (error) {
|
|
89
|
-
cleanupError = error;
|
|
90
|
-
}
|
|
91
|
-
try {
|
|
92
|
-
await fs.promises.unlink(original);
|
|
93
|
-
} catch (error) {
|
|
94
|
-
if (isMissingFileError(error) === false) cleanupError ??= error;
|
|
95
|
-
}
|
|
96
|
-
if (cleanupError !== void 0) throw new URIError(`Error on TypiaGenerateWizard.generate(): unable to clean filesystem case probe ${original}: ${formatUnknownError(cleanupError)}`);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
throw new URIError(`Error on TypiaGenerateWizard.generate(): unable to reserve a filesystem case probe at ${directory}.`);
|
|
100
|
-
}
|
|
101
|
-
_FileSystemIdentity.probeDirectory = probeDirectory;
|
|
102
|
-
function identityKey(stat, realpath) {
|
|
103
|
-
return stat.ino === BigInt(0) ? `path:${path.normalize(realpath)}` : `inode:${stat.dev}:${stat.ino}`;
|
|
104
|
-
}
|
|
105
|
-
_FileSystemIdentity.identityKey = identityKey;
|
|
106
|
-
function alternateCase(name) {
|
|
107
|
-
let changed = false;
|
|
108
|
-
let output = "";
|
|
109
|
-
for (const character of name) if (character >= "a" && character <= "z") {
|
|
110
|
-
output += character.toUpperCase();
|
|
111
|
-
changed = true;
|
|
112
|
-
} else if (character >= "A" && character <= "Z") {
|
|
113
|
-
output += character.toLowerCase();
|
|
114
|
-
changed = true;
|
|
115
|
-
} else output += character;
|
|
116
|
-
return changed ? output : void 0;
|
|
117
|
-
}
|
|
118
|
-
function isAlreadyExistsError(error) {
|
|
119
|
-
return typeof error === "object" && error !== null && "code" in error && error.code === "EEXIST";
|
|
120
|
-
}
|
|
121
|
-
function isMissingFileError(error) {
|
|
122
|
-
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
123
|
-
}
|
|
124
|
-
function formatUnknownError(error) {
|
|
125
|
-
return error instanceof Error ? error.message : String(error);
|
|
126
|
-
}
|
|
127
|
-
})(FileSystemIdentity || (FileSystemIdentity = {}));
|
|
128
|
-
const TS_PATTERN = /\.[cm]?tsx?$/;
|
|
129
|
-
const DTS_PATTERN = /\.d\.[cm]?tsx?$/;
|
|
130
|
-
//#endregion
|
|
131
|
-
export { FileSystemIdentity };
|
|
132
|
-
|
|
133
|
-
//# sourceMappingURL=FileSystemIdentity.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"FileSystemIdentity.mjs","names":[],"sources":["../../src/executable/FileSystemIdentity.ts"],"sourcesContent":["import fs from \"fs\";\nimport path from \"path\";\n\nexport namespace FileSystemIdentity {\n export interface IIdentity {\n readonly caseSensitive: boolean;\n contains(file: string, directory: string): boolean;\n filesystemKey(file: string): string;\n isDeclarationFile(file: string): boolean;\n isSamePath(x: string, y: string): boolean;\n isSupportedExtension(file: string): boolean;\n projectFileKey(file: string): string;\n }\n\n export function create(\n caseSensitive: boolean,\n pathApi: typeof path.posix = path,\n ): IIdentity {\n const fold = (value: string): string =>\n caseSensitive ? value : value.toLowerCase();\n const filesystemKey = (file: string): string =>\n fold(pathApi.normalize(file));\n return {\n caseSensitive,\n contains: (file, directory) => {\n const fileKey: string = filesystemKey(pathApi.resolve(file));\n const directoryKey: string = filesystemKey(pathApi.resolve(directory));\n const prefix: string = directoryKey.endsWith(pathApi.sep)\n ? directoryKey\n : `${directoryKey}${pathApi.sep}`;\n return fileKey === directoryKey || fileKey.startsWith(prefix);\n },\n filesystemKey,\n isDeclarationFile: (file) =>\n DTS_PATTERN.test(fold(pathApi.basename(file))),\n isSamePath: (x, y) => filesystemKey(x) === filesystemKey(y),\n isSupportedExtension: (file) => {\n const filename: string = fold(pathApi.basename(file));\n return (\n TS_PATTERN.test(filename) && DTS_PATTERN.test(filename) === false\n );\n },\n projectFileKey: fold,\n };\n }\n\n export class Policy {\n private caseSensitive_: boolean | undefined;\n private location_: string | undefined;\n\n public observe(caseSensitive: boolean | undefined, location: string): void {\n if (caseSensitive === undefined) return;\n if (this.caseSensitive_ === undefined) {\n this.caseSensitive_ = caseSensitive;\n this.location_ = location;\n } else if (this.caseSensitive_ !== caseSensitive) {\n throw new URIError(\n `Error on TypiaGenerateWizard.generate(): inconsistent filesystem case behavior between ${this.location_} and ${location}.`,\n );\n }\n }\n\n public get(): IIdentity {\n if (this.caseSensitive_ === undefined) {\n throw new URIError(\n \"Error on TypiaGenerateWizard.generate(): unable to determine filesystem case behavior for this run.\",\n );\n }\n return create(this.caseSensitive_);\n }\n }\n\n export async function inspectDirectory(\n directory: string,\n ): Promise<boolean | undefined> {\n const names: string[] = await fs.promises.readdir(directory);\n const entries: Set<string> = new Set(names);\n for (const name of names) {\n const alternate: string | undefined = alternateCase(name);\n if (alternate === undefined) continue;\n if (entries.has(alternate)) return true;\n try {\n await fs.promises.lstat(path.join(directory, alternate));\n return false;\n } catch (error) {\n if (isMissingFileError(error)) return true;\n throw error;\n }\n }\n return undefined;\n }\n\n export async function probeDirectory(directory: string): Promise<boolean> {\n const inspected: boolean | undefined = await inspectDirectory(directory);\n if (inspected !== undefined) return inspected;\n\n for (let attempt = 0; attempt < 10; ++attempt) {\n const name: string =\n `.typia-case-probe-${process.pid}-${Date.now()}-${Math.random()\n .toString(36)\n .slice(2)}`.toLowerCase();\n const original: string = path.join(directory, name);\n const alternate: string = path.join(directory, name.toUpperCase());\n let handle: fs.promises.FileHandle;\n try {\n handle = await fs.promises.open(original, \"wx\");\n } catch (error) {\n if (isAlreadyExistsError(error)) continue;\n throw new URIError(\n `Error on TypiaGenerateWizard.generate(): unable to probe filesystem case behavior at ${directory}: ${formatUnknownError(error)}`,\n );\n }\n let closed: boolean = false;\n try {\n await handle.close();\n closed = true;\n try {\n await fs.promises.lstat(alternate);\n return false;\n } catch (error) {\n if (isMissingFileError(error)) return true;\n throw error;\n }\n } finally {\n let cleanupError: unknown;\n if (closed === false) {\n try {\n await handle.close();\n } catch (error) {\n cleanupError = error;\n }\n }\n try {\n await fs.promises.unlink(original);\n } catch (error) {\n if (isMissingFileError(error) === false) cleanupError ??= error;\n }\n if (cleanupError !== undefined) {\n throw new URIError(\n `Error on TypiaGenerateWizard.generate(): unable to clean filesystem case probe ${original}: ${formatUnknownError(cleanupError)}`,\n );\n }\n }\n }\n throw new URIError(\n `Error on TypiaGenerateWizard.generate(): unable to reserve a filesystem case probe at ${directory}.`,\n );\n }\n\n /**\n * Builds the key that decides whether two paths are the same filesystem\n * object.\n *\n * The identity is read from `fs.BigIntStats` rather than `fs.Stats`, because\n * `fs.Stats.ino` is a JavaScript number. An NTFS file ID is `(sequenceNumber\n * << 48) | mftRecordIndex` and routinely exceeds `Number.MAX_SAFE_INTEGER` —\n * in a 4000-directory probe, 1879 of them did — where the spacing between\n * representable doubles is 8 or more. Two entries sharing a sequence number\n * with MFT record indices within that spacing round to one double. The\n * traversal callers would then treat a distinct directory or file as already\n * visited and skip it with no diagnostic, and the overwrite guard would\n * refuse a legitimate output (samchon/typia#2269).\n *\n * A filesystem that reports no inode at all keeps the canonical path\n * fallback, which is the only identity available there.\n *\n * @param stat Stats read with `{ bigint: true }`.\n * @param realpath Canonical path of the same object.\n * @returns Key that is equal for two paths only when they are one object.\n */\n export function identityKey(\n stat: Pick<fs.BigIntStats, \"dev\" | \"ino\">,\n realpath: string,\n ): string {\n // `BigInt(0)` rather than `0n`: this package compiles at ES2016, where a\n // BigInt literal is a syntax error, while the constructor and the `bigint`\n // type are fine.\n return stat.ino === BigInt(0)\n ? `path:${path.normalize(realpath)}`\n : `inode:${stat.dev}:${stat.ino}`;\n }\n\n function alternateCase(name: string): string | undefined {\n let changed: boolean = false;\n let output: string = \"\";\n for (const character of name) {\n if (character >= \"a\" && character <= \"z\") {\n output += character.toUpperCase();\n changed = true;\n } else if (character >= \"A\" && character <= \"Z\") {\n output += character.toLowerCase();\n changed = true;\n } else output += character;\n }\n return changed ? output : undefined;\n }\n\n function isAlreadyExistsError(error: unknown): boolean {\n return (\n typeof error === \"object\" &&\n error !== null &&\n \"code\" in error &&\n error.code === \"EEXIST\"\n );\n }\n\n function isMissingFileError(error: unknown): boolean {\n return (\n typeof error === \"object\" &&\n error !== null &&\n \"code\" in error &&\n error.code === \"ENOENT\"\n );\n }\n\n function formatUnknownError(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n }\n}\n\nconst TS_PATTERN = /\\.[cm]?tsx?$/;\nconst DTS_PATTERN = /\\.d\\.[cm]?tsx?$/;\n"],"mappings":";;;AAGO,IAAA;;CAWE,SAAS,OACd,eACA,UAA6B,MAClB;EACX,MAAM,QAAQ,UACZ,gBAAgB,QAAQ,MAAM,YAAY;EAC5C,MAAM,iBAAiB,SACrB,KAAK,QAAQ,UAAU,IAAI,CAAC;EAC9B,OAAO;GACL;GACA,WAAW,MAAM,cAAc;IAC7B,MAAM,UAAkB,cAAc,QAAQ,QAAQ,IAAI,CAAC;IAC3D,MAAM,eAAuB,cAAc,QAAQ,QAAQ,SAAS,CAAC;IACrE,MAAM,SAAiB,aAAa,SAAS,QAAQ,GAAG,IACpD,eACA,GAAG,eAAe,QAAQ;IAC9B,OAAO,YAAY,gBAAgB,QAAQ,WAAW,MAAM;GAC9D;GACA;GACA,oBAAoB,SAClB,YAAY,KAAK,KAAK,QAAQ,SAAS,IAAI,CAAC,CAAC;GAC/C,aAAa,GAAG,MAAM,cAAc,CAAC,MAAM,cAAc,CAAC;GAC1D,uBAAuB,SAAS;IAC9B,MAAM,WAAmB,KAAK,QAAQ,SAAS,IAAI,CAAC;IACpD,OACE,WAAW,KAAK,QAAQ,KAAK,YAAY,KAAK,QAAQ,MAAM;GAEhE;GACA,gBAAgB;EAClB;CACF;;CAEO,MAAM,OAAO;EAIlB,QAAe,eAAoC,UAAwB;GACzE,IAAI,kBAAkB,KAAA,GAAW;GACjC,IAAI,KAAK,mBAAmB,KAAA,GAAW;IACrC,KAAK,iBAAiB;IACtB,KAAK,YAAY;GACnB,OAAO,IAAI,KAAK,mBAAmB,eACjC,MAAM,IAAI,SACR,0FAA0F,KAAK,UAAU,OAAO,SAAS,EAC3H;EAEJ;EAEA,MAAwB;GACtB,IAAI,KAAK,mBAAmB,KAAA,GAC1B,MAAM,IAAI,SACR,qGACF;GAEF,OAAO,OAAO,KAAK,cAAc;EACnC;CACF;;CAEO,eAAe,iBACpB,WAC8B;EAC9B,MAAM,QAAkB,MAAM,GAAG,SAAS,QAAQ,SAAS;EAC3D,MAAM,UAAuB,IAAI,IAAI,KAAK;EAC1C,KAAK,MAAM,QAAQ,OAAO;GACxB,MAAM,YAAgC,cAAc,IAAI;GACxD,IAAI,cAAc,KAAA,GAAW;GAC7B,IAAI,QAAQ,IAAI,SAAS,GAAG,OAAO;GACnC,IAAI;IACF,MAAM,GAAG,SAAS,MAAM,KAAK,KAAK,WAAW,SAAS,CAAC;IACvD,OAAO;GACT,SAAS,OAAO;IACd,IAAI,mBAAmB,KAAK,GAAG,OAAO;IACtC,MAAM;GACR;EACF;CAEF;;CAEO,eAAe,eAAe,WAAqC;EACxE,MAAM,YAAiC,MAAM,iBAAiB,SAAS;EACvE,IAAI,cAAc,KAAA,GAAW,OAAO;EAEpC,KAAK,IAAI,UAAU,GAAG,UAAU,IAAI,EAAE,SAAS;GAC7C,MAAM,OACJ,qBAAqB,QAAQ,IAAI,GAAG,KAAK,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC,CAC5D,SAAS,EAAE,CAAC,CACZ,MAAM,CAAC,IAAI,YAAY;GAC5B,MAAM,WAAmB,KAAK,KAAK,WAAW,IAAI;GAClD,MAAM,YAAoB,KAAK,KAAK,WAAW,KAAK,YAAY,CAAC;GACjE,IAAI;GACJ,IAAI;IACF,SAAS,MAAM,GAAG,SAAS,KAAK,UAAU,IAAI;GAChD,SAAS,OAAO;IACd,IAAI,qBAAqB,KAAK,GAAG;IACjC,MAAM,IAAI,SACR,wFAAwF,UAAU,IAAI,mBAAmB,KAAK,GAChI;GACF;GACA,IAAI,SAAkB;GACtB,IAAI;IACF,MAAM,OAAO,MAAM;IACnB,SAAS;IACT,IAAI;KACF,MAAM,GAAG,SAAS,MAAM,SAAS;KACjC,OAAO;IACT,SAAS,OAAO;KACd,IAAI,mBAAmB,KAAK,GAAG,OAAO;KACtC,MAAM;IACR;GACF,UAAU;IACR,IAAI;IACJ,IAAI,WAAW,OACb,IAAI;KACF,MAAM,OAAO,MAAM;IACrB,SAAS,OAAO;KACd,eAAe;IACjB;IAEF,IAAI;KACF,MAAM,GAAG,SAAS,OAAO,QAAQ;IACnC,SAAS,OAAO;KACd,IAAI,mBAAmB,KAAK,MAAM,OAAO,iBAAiB;IAC5D;IACA,IAAI,iBAAiB,KAAA,GACnB,MAAM,IAAI,SACR,kFAAkF,SAAS,IAAI,mBAAmB,YAAY,GAChI;GAEJ;EACF;EACA,MAAM,IAAI,SACR,yFAAyF,UAAU,EACrG;CACF;;CAuBO,SAAS,YACd,MACA,UACQ;EAIR,OAAO,KAAK,QAAQ,OAAO,CAAC,IACxB,QAAQ,KAAK,UAAU,QAAQ,MAC/B,SAAS,KAAK,IAAI,GAAG,KAAK;CAChC;;CAEA,SAAS,cAAc,MAAkC;EACvD,IAAI,UAAmB;EACvB,IAAI,SAAiB;EACrB,KAAK,MAAM,aAAa,MACtB,IAAI,aAAa,OAAO,aAAa,KAAK;GACxC,UAAU,UAAU,YAAY;GAChC,UAAU;EACZ,OAAO,IAAI,aAAa,OAAO,aAAa,KAAK;GAC/C,UAAU,UAAU,YAAY;GAChC,UAAU;EACZ,OAAO,UAAU;EAEnB,OAAO,UAAU,SAAS,KAAA;CAC5B;CAEA,SAAS,qBAAqB,OAAyB;EACrD,OACE,OAAO,UAAU,YACjB,UAAU,QACV,UAAU,SACV,MAAM,SAAS;CAEnB;CAEA,SAAS,mBAAmB,OAAyB;EACnD,OACE,OAAO,UAAU,YACjB,UAAU,QACV,UAAU,SACV,MAAM,SAAS;CAEnB;CAEA,SAAS,mBAAmB,OAAwB;EAClD,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;CAC9D;GACD,uBAAA,qBAAA,CAAA,EAAD;AAEA,MAAM,aAAa;AACnB,MAAM,cAAc"}
|