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.
Files changed (84) hide show
  1. package/lib/internal/_createStandardSchema.d.ts +1 -2
  2. package/lib/internal/_createStandardSchema.js.map +1 -1
  3. package/lib/internal/_createStandardSchema.mjs.map +1 -1
  4. package/lib/internal/_randomPattern.js +20 -3
  5. package/lib/internal/_randomPattern.js.map +1 -1
  6. package/lib/internal/_randomPattern.mjs +5 -1
  7. package/lib/internal/_randomPattern.mjs.map +1 -1
  8. package/lib/internal/_randomStringLength.js +9 -2
  9. package/lib/internal/_randomStringLength.js.map +1 -1
  10. package/lib/internal/_randomStringLength.mjs +3 -1
  11. package/lib/internal/_randomStringLength.mjs.map +1 -1
  12. package/lib/module.d.ts +1 -2
  13. package/lib/module.js.map +1 -1
  14. package/lib/module.mjs.map +1 -1
  15. package/lib/re-exports.d.ts +1 -1
  16. package/lib/re-exports.js.map +1 -1
  17. package/lib/transform.mjs +1 -1
  18. package/native/cmd/ttsc-typia/create_assert_error_factory_arity_test.go +5 -2
  19. package/native/cmd/ttsc-typia/dependency_collector_virtual_scheme_test.go +52 -0
  20. package/native/cmd/ttsc-typia/dynamic_key_tags_transform_test.go +206 -0
  21. package/native/cmd/ttsc-typia/notation_kebab_case_transform_test.go +2 -2
  22. package/native/cmd/ttsc-typia/project_catalog_transform_coverage_test.go +84 -85
  23. package/native/cmd/ttsc-typia/project_dependencies_callee_argument_transform_test.go +177 -0
  24. package/native/cmd/ttsc-typia/project_dependencies_callee_barrel_transform_test.go +115 -0
  25. package/native/cmd/ttsc-typia/project_dependencies_callee_inference_transform_test.go +285 -0
  26. package/native/cmd/ttsc-typia/project_dependencies_callee_shape_transform_test.go +117 -0
  27. package/native/cmd/ttsc-typia/project_dependencies_callee_untransformed_barrel_transform_test.go +121 -0
  28. package/native/cmd/ttsc-typia/project_dependencies_complete_diagnostic_transform_test.go +116 -0
  29. package/native/cmd/ttsc-typia/project_dependencies_complete_envelope_transform_test.go +115 -0
  30. package/native/cmd/ttsc-typia/project_dependencies_complete_inferred_type_transform_test.go +127 -0
  31. package/native/cmd/ttsc-typia/project_dependencies_complete_replaced_library_transform_test.go +153 -0
  32. package/native/cmd/ttsc-typia/project_dependencies_complete_untouched_reprint_transform_test.go +155 -0
  33. package/native/cmd/ttsc-typia/project_dependencies_computed_key_transform_test.go +218 -0
  34. package/native/cmd/ttsc-typia/project_dependencies_custom_lib_name_transform_test.go +6 -5
  35. package/native/cmd/ttsc-typia/project_dependencies_enum_member_value_transform_test.go +131 -0
  36. package/native/cmd/ttsc-typia/project_dependencies_inferred_declaration_transform_test.go +159 -0
  37. package/native/cmd/ttsc-typia/project_dependencies_jsdoc_typedef_transform_test.go +134 -0
  38. package/native/cmd/ttsc-typia/project_dependencies_named_tuple_member_transform_test.go +123 -0
  39. package/native/cmd/ttsc-typia/project_dependencies_qualified_barrel_transform_test.go +141 -0
  40. package/native/cmd/ttsc-typia/project_dependencies_type_parameter_default_transform_test.go +127 -0
  41. package/native/cmd/ttsc-typia/template_literal_type_tags_transform_test.go +3 -1
  42. package/native/cmd/ttsc-typia/transform.go +195 -21
  43. package/native/cmd/ttsc-typia/transform_helpers_test.go +12 -0
  44. package/native/core/factories/MetadataCommentTagFactory.go +96 -27
  45. package/native/core/factories/metadata_comment_tag_factory_coverage_test.go +2 -2
  46. package/native/core/factories/metadata_comment_tag_factory_rejects_out_of_range_integer_test.go +124 -0
  47. package/native/core/programmers/AssertProgrammer.go +20 -6
  48. package/native/core/programmers/RandomProgrammer.go +78 -6
  49. package/native/core/programmers/ValidateProgrammer.go +21 -6
  50. package/native/core/programmers/helpers/RandomJoiner.go +8 -1
  51. package/native/core/programmers/iterate/check_dynamic_properties.go +177 -3
  52. package/native/core/programmers/iterate/check_object.go +12 -1
  53. package/native/core/schemas/metadata/MetadataDependency.go +613 -30
  54. package/native/transform/CallExpressionTransformer.go +16 -1
  55. package/package.json +4 -14
  56. package/src/internal/_createStandardSchema.ts +1 -2
  57. package/src/internal/_randomPattern.ts +18 -3
  58. package/src/internal/_randomStringLength.ts +9 -2
  59. package/src/module.ts +6 -2
  60. package/src/re-exports.ts +13 -0
  61. package/lib/executable/FileSystemIdentity.d.ts +0 -44
  62. package/lib/executable/FileSystemIdentity.js +0 -213
  63. package/lib/executable/FileSystemIdentity.js.map +0 -1
  64. package/lib/executable/FileSystemIdentity.mjs +0 -133
  65. package/lib/executable/FileSystemIdentity.mjs.map +0 -1
  66. package/lib/executable/TypiaGenerateWizard.d.ts +0 -9
  67. package/lib/executable/TypiaGenerateWizard.js +0 -852
  68. package/lib/executable/TypiaGenerateWizard.js.map +0 -1
  69. package/lib/executable/TypiaGenerateWizard.mjs +0 -618
  70. package/lib/executable/TypiaGenerateWizard.mjs.map +0 -1
  71. package/lib/executable/generate/ttsc.d.ts +0 -1
  72. package/lib/executable/generate/ttsc.js +0 -53
  73. package/lib/executable/generate/ttsc.js.map +0 -1
  74. package/lib/executable/generate/ttsc.mjs +0 -37
  75. package/lib/executable/generate/ttsc.mjs.map +0 -1
  76. package/lib/executable/typia.d.ts +0 -2
  77. package/lib/executable/typia.js +0 -84
  78. package/lib/executable/typia.js.map +0 -1
  79. package/lib/executable/typia.mjs +0 -60
  80. package/lib/executable/typia.mjs.map +0 -1
  81. package/src/executable/FileSystemIdentity.ts +0 -222
  82. package/src/executable/TypiaGenerateWizard.ts +0 -1133
  83. package/src/executable/generate/ttsc.ts +0 -70
  84. 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
- if props.Expression.TypeArguments != nil {
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": "13.3.0",
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
- "tinyglobby": "^0.2.12",
53
- "@typia/interface": "^13.3.0",
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
- "suppress-warnings": "^1.0.2",
71
- "ttsc": "^0.19.2",
61
+ "ttsc": "^0.28.1",
72
62
  "typescript": "^7.0.2"
73
63
  },
74
64
  "sideEffects": false,
@@ -1,5 +1,4 @@
1
- import { StandardSchemaV1 } from "@standard-schema/spec";
2
- import { IValidation } from "@typia/interface";
1
+ import { IValidation, StandardSchemaV1 } from "@typia/interface";
3
2
 
4
3
  export const _createStandardSchema = <T>(
5
4
  fn: (input: unknown) => IValidation<T>,
@@ -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
- regex.test(str) &&
25
- (min === undefined || str.length >= min) &&
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 || value.length >= props.minLength) &&
111
- (props.maxLength === undefined || value.length <= props.maxLength)
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 { StandardSchemaV1 } from "@standard-schema/spec";
2
- import { IRandomGenerator, IValidation, Resolved } from "@typia/interface";
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"}
@@ -1,9 +0,0 @@
1
- export declare namespace TypiaGenerateWizard {
2
- function generate(): Promise<void>;
3
- interface IArguments {
4
- input?: string;
5
- output: string;
6
- project: string;
7
- files: string[];
8
- }
9
- }