sizuku 0.0.7 → 0.2.0
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/README.md +96 -344
- package/dist/cli/main.d.ts +10 -0
- package/dist/cli/main.js +61 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +51 -0
- package/dist/config/index.d.ts +18 -0
- package/dist/config/index.js +13 -0
- package/dist/config/loader.d.ts +19 -0
- package/dist/config/loader.js +30 -0
- package/dist/generator/engine.d.ts +3 -0
- package/dist/generator/engine.js +63 -0
- package/dist/generator/mermaid-er/config/index.d.ts +4 -4
- package/dist/generator/mermaid-er/config/index.js +4 -10
- package/dist/generator/mermaid-er/core/extract-relations.d.ts +1 -1
- package/dist/generator/mermaid-er/core/extract-relations.js +3 -6
- package/dist/generator/mermaid-er/core.d.ts +6 -0
- package/dist/generator/mermaid-er/core.js +54 -0
- package/dist/generator/mermaid-er/generator/er-content.d.ts +20 -0
- package/dist/generator/mermaid-er/generator/{generate-er-content.js → er-content.js} +3 -7
- package/dist/generator/mermaid-er/generator/index.d.ts +2 -0
- package/dist/generator/mermaid-er/generator/index.js +2 -0
- package/dist/generator/mermaid-er/generator/relation-line.d.ts +12 -0
- package/dist/generator/mermaid-er/generator/{generate-relation-line.js → relation-line.js} +3 -6
- package/dist/generator/mermaid-er/generator.d.ts +3 -0
- package/dist/generator/mermaid-er/generator.js +14 -0
- package/dist/generator/mermaid-er/index.d.ts +12 -5
- package/dist/generator/mermaid-er/index.js +30 -74
- package/dist/generator/mermaid-er/relationship/build-relation-line.js +3 -6
- package/dist/generator/mermaid-er/types.js +1 -0
- package/dist/generator/mermaid-er/validator/index.d.ts +8 -0
- package/dist/generator/mermaid-er/validator/index.js +71 -0
- package/dist/generator/mermaid-er/validator/is-relationship.d.ts +1 -1
- package/dist/generator/mermaid-er/validator/is-relationship.js +1 -4
- package/dist/generator/mermaid-er/validator/parse-relation-line.js +1 -4
- package/dist/generator/mermaid-er/validator/parse-table-info.d.ts +1 -7
- package/dist/generator/mermaid-er/validator/parse-table-info.js +69 -89
- package/dist/generator/mermaid-er/validator/remove-duplicate-relations.js +1 -4
- package/dist/generator/valibot/config/index.d.ts +2 -2
- package/dist/generator/valibot/config/index.js +6 -12
- package/dist/generator/valibot/core/extract-schema.d.ts +2 -5
- package/dist/generator/valibot/core/extract-schema.js +162 -81
- package/dist/generator/valibot/core.d.ts +5 -0
- package/dist/generator/valibot/core.js +39 -0
- package/dist/generator/valibot/generator/infer-input.d.ts +5 -0
- package/dist/generator/valibot/generator/infer-input.js +8 -0
- package/dist/generator/valibot/generator/relation-valibot-code.d.ts +13 -0
- package/dist/generator/valibot/generator/relation-valibot-code.js +19 -0
- package/dist/generator/valibot/generator/valibot-code.d.ts +15 -0
- package/dist/generator/valibot/generator/valibot-code.js +16 -0
- package/dist/generator/valibot/generator/valibot.d.ts +14 -0
- package/dist/generator/valibot/generator/valibot.js +15 -0
- package/dist/generator/valibot/generator.d.ts +3 -0
- package/dist/generator/valibot/generator.js +14 -0
- package/dist/generator/valibot/index.d.ts +14 -3
- package/dist/generator/valibot/index.js +46 -73
- package/dist/generator/zod/config/index.d.ts +2 -2
- package/dist/generator/zod/config/index.js +6 -12
- package/dist/generator/zod/core/extract-schema.d.ts +1 -2
- package/dist/generator/zod/core/extract-schema.js +228 -81
- package/dist/generator/zod/core.d.ts +5 -0
- package/dist/generator/zod/core.js +39 -0
- package/dist/generator/zod/generator/infer.d.ts +5 -0
- package/dist/generator/zod/generator/infer.js +8 -0
- package/dist/generator/zod/generator/relation-zod-code.d.ts +13 -0
- package/dist/generator/zod/generator/relation-zod-code.js +19 -0
- package/dist/generator/zod/generator/zod-code.d.ts +17 -0
- package/dist/generator/zod/generator/zod-code.js +18 -0
- package/dist/generator/zod/generator/zod.d.ts +16 -0
- package/dist/generator/zod/generator/zod.js +16 -0
- package/dist/generator/zod/generator.d.ts +3 -0
- package/dist/generator/zod/generator.js +14 -0
- package/dist/generator/zod/index.d.ts +15 -3
- package/dist/generator/zod/index.js +50 -73
- package/dist/index.d.ts +8 -0
- package/dist/index.js +71 -0
- package/dist/shared/config/index.d.ts +13 -0
- package/dist/{common → shared}/config/index.js +1 -4
- package/dist/shared/format/index.d.ts +15 -0
- package/dist/shared/format/index.js +24 -0
- package/dist/shared/fs/index.d.ts +7 -0
- package/dist/shared/fs/index.js +16 -0
- package/dist/shared/fsp/index.d.ts +27 -0
- package/dist/shared/fsp/index.js +38 -0
- package/dist/shared/generator/field-definitions.d.ts +12 -0
- package/dist/shared/generator/field-definitions.js +12 -0
- package/dist/shared/helper/ast-parser.d.ts +3 -0
- package/dist/shared/helper/ast-parser.js +202 -0
- package/dist/shared/helper/build-schema-extractor.d.ts +25 -0
- package/dist/shared/helper/build-schema-extractor.js +33 -0
- package/dist/shared/helper/create-extract-field-from-property.d.ts +15 -0
- package/dist/shared/helper/create-extract-field-from-property.js +20 -0
- package/dist/shared/helper/create-extract-fields-from-call-expression.d.ts +14 -0
- package/dist/shared/helper/create-extract-fields-from-call-expression.js +14 -0
- package/dist/shared/helper/create-extract-relation-field-from-property.d.ts +12 -0
- package/dist/shared/helper/create-extract-relation-field-from-property.js +27 -0
- package/dist/shared/helper/extract-schemas.d.ts +133 -0
- package/dist/shared/helper/extract-schemas.js +445 -0
- package/dist/shared/helper/file-writer.d.ts +3 -0
- package/dist/shared/helper/file-writer.js +25 -0
- package/dist/shared/helper/find-object-literal-expression.d.ts +12 -0
- package/dist/shared/helper/find-object-literal-expression.js +31 -0
- package/dist/shared/helper/find-object-literalIn-args.d.ts +2 -0
- package/dist/shared/helper/find-object-literalIn-args.js +8 -0
- package/dist/shared/helper/is-relation-function.d.ts +10 -0
- package/dist/shared/helper/is-relation-function.js +16 -0
- package/dist/shared/types.js +1 -0
- package/dist/{common/text → shared/utils}/capitalize.js +1 -4
- package/dist/shared/utils/compose.d.ts +101 -0
- package/dist/shared/utils/compose.js +124 -0
- package/dist/shared/utils/file.d.ts +92 -0
- package/dist/shared/utils/file.js +177 -0
- package/dist/shared/utils/functional.d.ts +118 -0
- package/dist/shared/utils/functional.js +96 -0
- package/dist/shared/utils/index.d.ts +20 -0
- package/dist/shared/utils/index.js +48 -0
- package/dist/shared/utils/string-utils.d.ts +8 -0
- package/dist/shared/utils/string-utils.js +28 -0
- package/dist/shared/utils/types.d.ts +32 -0
- package/dist/shared/utils/types.js +2 -0
- package/dist/shared/utils/validation-utils.d.ts +8 -0
- package/dist/shared/utils/validation-utils.js +25 -0
- package/dist/src/config/index.d.ts +18 -0
- package/dist/src/config/index.js +13 -0
- package/dist/src/generator/mermaid-er/core/extract-relations.d.ts +8 -0
- package/dist/src/generator/mermaid-er/core/extract-relations.js +12 -0
- package/dist/src/generator/mermaid-er/generator/er-content.d.ts +9 -0
- package/dist/src/generator/mermaid-er/generator/er-content.js +25 -0
- package/dist/src/generator/mermaid-er/generator/index.d.ts +2 -0
- package/dist/src/generator/mermaid-er/generator/index.js +2 -0
- package/dist/src/generator/mermaid-er/generator/relation-line.d.ts +8 -0
- package/dist/src/generator/mermaid-er/generator/relation-line.js +14 -0
- package/dist/src/generator/mermaid-er/index.d.ts +6 -0
- package/dist/src/generator/mermaid-er/index.js +16 -0
- package/dist/src/generator/mermaid-er/relationship/build-relation-line.d.ts +15 -0
- package/dist/src/generator/mermaid-er/relationship/build-relation-line.js +35 -0
- package/dist/src/generator/mermaid-er/types.d.ts +21 -0
- package/dist/src/generator/mermaid-er/types.js +1 -0
- package/dist/src/generator/mermaid-er/validator/index.d.ts +4 -0
- package/dist/src/generator/mermaid-er/validator/index.js +4 -0
- package/dist/src/generator/mermaid-er/validator/is-relationship.d.ts +8 -0
- package/dist/src/generator/mermaid-er/validator/is-relationship.js +9 -0
- package/dist/src/generator/mermaid-er/validator/parse-relation-line.d.ts +13 -0
- package/dist/src/generator/mermaid-er/validator/parse-relation-line.js +21 -0
- package/dist/src/generator/mermaid-er/validator/parse-table-info.d.ts +8 -0
- package/dist/src/generator/mermaid-er/validator/parse-table-info.js +91 -0
- package/dist/src/generator/mermaid-er/validator/remove-duplicate-relations.d.ts +7 -0
- package/dist/src/generator/mermaid-er/validator/remove-duplicate-relations.js +9 -0
- package/dist/src/generator/valibot/generator/infer-input.d.ts +5 -0
- package/dist/src/generator/valibot/generator/infer-input.js +8 -0
- package/dist/src/generator/valibot/generator/valibot-code.d.ts +14 -0
- package/dist/src/generator/valibot/generator/valibot-code.js +16 -0
- package/dist/src/generator/valibot/generator/valibot.d.ts +13 -0
- package/dist/src/generator/valibot/generator/valibot.js +11 -0
- package/dist/src/generator/valibot/index.d.ts +9 -0
- package/dist/src/generator/valibot/index.js +34 -0
- package/dist/src/generator/zod/generator/infer.d.ts +5 -0
- package/dist/src/generator/zod/generator/infer.js +8 -0
- package/dist/{generator/zod/generator/generate-zod-code.d.ts → src/generator/zod/generator/zod-code.d.ts} +8 -3
- package/dist/src/generator/zod/generator/zod-code.js +18 -0
- package/dist/{generator/zod/generator/generate-zod-schema.d.ts → src/generator/zod/generator/zod.d.ts} +8 -4
- package/dist/src/generator/zod/generator/zod.js +12 -0
- package/dist/src/generator/zod/index.d.ts +10 -0
- package/dist/src/generator/zod/index.js +40 -0
- package/dist/src/index.d.ts +10 -0
- package/dist/src/index.js +35 -0
- package/dist/src/shared/format/index.d.ts +2 -0
- package/dist/src/shared/format/index.js +10 -0
- package/dist/src/shared/fs/index.d.ts +2 -0
- package/dist/src/shared/fs/index.js +10 -0
- package/dist/src/shared/fsp/index.d.ts +3 -0
- package/dist/src/shared/fsp/index.js +8 -0
- package/dist/src/shared/generator/field-definitions.d.ts +12 -0
- package/dist/src/shared/generator/field-definitions.js +12 -0
- package/dist/src/shared/helper/build-schema-extractor.d.ts +25 -0
- package/dist/src/shared/helper/build-schema-extractor.js +33 -0
- package/dist/src/shared/helper/create-extract-field-from-property.d.ts +15 -0
- package/dist/src/shared/helper/create-extract-field-from-property.js +20 -0
- package/dist/src/shared/helper/create-extract-fields-from-call-expression.d.ts +14 -0
- package/dist/src/shared/helper/create-extract-fields-from-call-expression.js +14 -0
- package/dist/src/shared/helper/create-extract-relation-field-from-property.d.ts +12 -0
- package/dist/src/shared/helper/create-extract-relation-field-from-property.js +27 -0
- package/dist/src/shared/helper/extract-schemas.d.ts +16 -0
- package/dist/src/shared/helper/extract-schemas.js +19 -0
- package/dist/src/shared/helper/find-object-literal-expression.d.ts +12 -0
- package/dist/src/shared/helper/find-object-literal-expression.js +31 -0
- package/dist/src/shared/helper/find-object-literalIn-args.d.ts +2 -0
- package/dist/src/shared/helper/find-object-literalIn-args.js +8 -0
- package/dist/src/shared/helper/is-relation-function.d.ts +10 -0
- package/dist/src/shared/helper/is-relation-function.js +16 -0
- package/dist/src/shared/utils/index.d.ts +33 -0
- package/dist/src/shared/utils/index.js +61 -0
- package/dist/utils/index.d.ts +144 -0
- package/dist/utils/index.js +301 -0
- package/package.json +10 -13
- package/dist/common/config/index.d.ts +0 -13
- package/dist/common/format/index.d.ts +0 -1
- package/dist/common/format/index.js +0 -12
- package/dist/common/generator/generate-field-definitions.d.ts +0 -8
- package/dist/common/generator/generate-field-definitions.js +0 -16
- package/dist/common/helper/get-camel-case-schema-name-helper.d.ts +0 -7
- package/dist/common/helper/get-camel-case-schema-name-helper.js +0 -14
- package/dist/common/helper/get-pascal-case-schema-name-helper.d.ts +0 -8
- package/dist/common/helper/get-pascal-case-schema-name-helper.js +0 -15
- package/dist/common/helper/get-variable-name-helper.d.ts +0 -9
- package/dist/common/helper/get-variable-name-helper.js +0 -15
- package/dist/common/helper/get-variable-schema-name-helper.d.ts +0 -9
- package/dist/common/helper/get-variable-schema-name-helper.js +0 -17
- package/dist/common/text/decapitalize.d.ts +0 -17
- package/dist/common/text/decapitalize.js +0 -22
- package/dist/common/type/index.js +0 -2
- package/dist/generator/mermaid-er/generator/generate-er-content.d.ts +0 -9
- package/dist/generator/mermaid-er/generator/generate-relation-line.d.ts +0 -7
- package/dist/generator/mermaid-er/type/index.js +0 -2
- package/dist/generator/mermaid-er/validator/is-relation.d.ts +0 -7
- package/dist/generator/mermaid-er/validator/is-relation.js +0 -40
- package/dist/generator/valibot/generator/generate-valibot-code.d.ts +0 -11
- package/dist/generator/valibot/generator/generate-valibot-code.js +0 -21
- package/dist/generator/valibot/generator/generate-valibot-infer-input.d.ts +0 -9
- package/dist/generator/valibot/generator/generate-valibot-infer-input.js +0 -16
- package/dist/generator/valibot/generator/generate-valibot-schema.d.ts +0 -9
- package/dist/generator/valibot/generator/generate-valibot-schema.js +0 -16
- package/dist/generator/zod/generator/generate-z-infer.d.ts +0 -11
- package/dist/generator/zod/generator/generate-z-infer.js +0 -18
- package/dist/generator/zod/generator/generate-zod-code.js +0 -21
- package/dist/generator/zod/generator/generate-zod-schema.js +0 -17
- /package/dist/generator/mermaid-er/{type/index.d.ts → types.d.ts} +0 -0
- /package/dist/{common/type/index.d.ts → shared/types.d.ts} +0 -0
- /package/dist/{common/text → shared/utils}/capitalize.d.ts +0 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Capitalize the first letter of a string.
|
|
3
|
+
*
|
|
4
|
+
* @param str - The input string.
|
|
5
|
+
* @returns A new string with the first letter capitalized.
|
|
6
|
+
*/
|
|
7
|
+
export declare function capitalize(str: string): string;
|
|
8
|
+
/**
|
|
9
|
+
* Remove triple slash prefix from a string.
|
|
10
|
+
*
|
|
11
|
+
* @param str - The input string.
|
|
12
|
+
* @returns String with triple slash prefix removed.
|
|
13
|
+
*/
|
|
14
|
+
export declare function removeTripleSlash(str: string): string;
|
|
15
|
+
/**
|
|
16
|
+
* Check if a string is non-empty.
|
|
17
|
+
*
|
|
18
|
+
* @param str - The input string.
|
|
19
|
+
* @returns True if string is non-empty.
|
|
20
|
+
*/
|
|
21
|
+
export declare function isNonEmpty(str: string): boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Check if a string contains a substring.
|
|
24
|
+
*
|
|
25
|
+
* @param str - The input string.
|
|
26
|
+
* @param substr - The substring to search for.
|
|
27
|
+
* @returns True if string contains substring.
|
|
28
|
+
*/
|
|
29
|
+
export declare function containsSubstring(str: string, substr: string): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Check if a string starts with a prefix.
|
|
32
|
+
*
|
|
33
|
+
* @param str - The input string.
|
|
34
|
+
* @param prefix - The prefix to check.
|
|
35
|
+
* @returns True if string starts with prefix.
|
|
36
|
+
*/
|
|
37
|
+
export declare function startsWith(str: string, prefix: string): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Remove @ sign from the beginning of a string.
|
|
40
|
+
*
|
|
41
|
+
* @param str - The input string.
|
|
42
|
+
* @returns String with @ sign removed.
|
|
43
|
+
*/
|
|
44
|
+
export declare function removeAtSign(str: string): string;
|
|
45
|
+
/**
|
|
46
|
+
* Join array of strings with space separator.
|
|
47
|
+
*
|
|
48
|
+
* @param arr - Array of strings to join.
|
|
49
|
+
* @returns Joined string with spaces.
|
|
50
|
+
*/
|
|
51
|
+
export declare function joinWithSpace(arr: string[]): string;
|
|
52
|
+
/**
|
|
53
|
+
* Split string by newline character.
|
|
54
|
+
*
|
|
55
|
+
* @param str - The input string.
|
|
56
|
+
* @returns Array of strings split by newline.
|
|
57
|
+
*/
|
|
58
|
+
export declare function splitByNewline(str: string): string[];
|
|
59
|
+
/**
|
|
60
|
+
* Trim whitespace from string.
|
|
61
|
+
*
|
|
62
|
+
* @param str - The input string.
|
|
63
|
+
* @returns Trimmed string.
|
|
64
|
+
*/
|
|
65
|
+
export declare function trimString(str: string): string;
|
|
66
|
+
/**
|
|
67
|
+
* Parse relation line and extract components.
|
|
68
|
+
*
|
|
69
|
+
* @param line - The line to parse.
|
|
70
|
+
* @returns Parsed relation or null if not a relation line.
|
|
71
|
+
*/
|
|
72
|
+
export declare function parseRelationLine(line: string): {
|
|
73
|
+
fromModel: string;
|
|
74
|
+
toModel: string;
|
|
75
|
+
fromField: string;
|
|
76
|
+
toField: string;
|
|
77
|
+
type: string;
|
|
78
|
+
} | null;
|
|
79
|
+
/**
|
|
80
|
+
* Split string by '-to-' delimiter.
|
|
81
|
+
*
|
|
82
|
+
* @param str - The input string.
|
|
83
|
+
* @returns Array with two parts or null if not found.
|
|
84
|
+
*/
|
|
85
|
+
export declare function splitByTo(str: string): [string, string] | null;
|
|
86
|
+
/**
|
|
87
|
+
* Remove optional suffix from string.
|
|
88
|
+
*
|
|
89
|
+
* @param str - The input string.
|
|
90
|
+
* @returns String with optional suffix removed.
|
|
91
|
+
*/
|
|
92
|
+
export declare function removeOptionalSuffix(str: string): string;
|
|
93
|
+
/**
|
|
94
|
+
* Split string by whitespace.
|
|
95
|
+
*
|
|
96
|
+
* @param str - The input string.
|
|
97
|
+
* @returns Array of strings split by whitespace.
|
|
98
|
+
*/
|
|
99
|
+
export declare function splitByWhitespace(str: string): string[];
|
|
100
|
+
/**
|
|
101
|
+
* Split string by dot character.
|
|
102
|
+
*
|
|
103
|
+
* @param str - The input string.
|
|
104
|
+
* @returns Array of strings split by dot.
|
|
105
|
+
*/
|
|
106
|
+
export declare function splitByDot(str: string): string[];
|
|
107
|
+
/**
|
|
108
|
+
* Parse field comments and extract definition line and description.
|
|
109
|
+
*
|
|
110
|
+
* @param commentLines - Raw comment lines (e.g., from source text)
|
|
111
|
+
* @param tag - The tag to look for (e.g., '@v.' or '@z.')
|
|
112
|
+
* @returns Parsed definition and description
|
|
113
|
+
*/
|
|
114
|
+
export declare function parseFieldComments(commentLines: string[], tag: '@v.' | '@z.'): {
|
|
115
|
+
definition: string;
|
|
116
|
+
description?: string;
|
|
117
|
+
objectType?: 'strict' | 'loose';
|
|
118
|
+
};
|
|
119
|
+
/**
|
|
120
|
+
* Extract field comments from source text.
|
|
121
|
+
*
|
|
122
|
+
* @param sourceText - The source text to extract comments from.
|
|
123
|
+
* @param fieldStartPos - The position of the field in the source text.
|
|
124
|
+
* @returns An array of comment lines.
|
|
125
|
+
*/
|
|
126
|
+
export declare function extractFieldComments(sourceText: string, fieldStartPos: number): string[];
|
|
127
|
+
/**
|
|
128
|
+
* @param name
|
|
129
|
+
* @returns
|
|
130
|
+
*/
|
|
131
|
+
export declare function infer(name: string): string;
|
|
132
|
+
export declare function inferInput(name: string): string;
|
|
133
|
+
/**
|
|
134
|
+
* @param schema
|
|
135
|
+
* @returns
|
|
136
|
+
*/
|
|
137
|
+
export declare function fieldDefinitions(schema: {
|
|
138
|
+
name: string;
|
|
139
|
+
fields: {
|
|
140
|
+
name: string;
|
|
141
|
+
definition: string;
|
|
142
|
+
description?: string;
|
|
143
|
+
}[];
|
|
144
|
+
}, comment: boolean): string;
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
/* ========================================================================== *
|
|
2
|
+
* text
|
|
3
|
+
* ========================================================================== */
|
|
4
|
+
/**
|
|
5
|
+
* Capitalize the first letter of a string.
|
|
6
|
+
*
|
|
7
|
+
* @param str - The input string.
|
|
8
|
+
* @returns A new string with the first letter capitalized.
|
|
9
|
+
*/
|
|
10
|
+
export function capitalize(str) {
|
|
11
|
+
return `${str.charAt(0).toUpperCase()}${str.slice(1)}`;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Remove triple slash prefix from a string.
|
|
15
|
+
*
|
|
16
|
+
* @param str - The input string.
|
|
17
|
+
* @returns String with triple slash prefix removed.
|
|
18
|
+
*/
|
|
19
|
+
export function removeTripleSlash(str) {
|
|
20
|
+
return str.startsWith('///') ? str.substring(3) : str;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Check if a string is non-empty.
|
|
24
|
+
*
|
|
25
|
+
* @param str - The input string.
|
|
26
|
+
* @returns True if string is non-empty.
|
|
27
|
+
*/
|
|
28
|
+
export function isNonEmpty(str) {
|
|
29
|
+
return str.length > 0;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Check if a string contains a substring.
|
|
33
|
+
*
|
|
34
|
+
* @param str - The input string.
|
|
35
|
+
* @param substr - The substring to search for.
|
|
36
|
+
* @returns True if string contains substring.
|
|
37
|
+
*/
|
|
38
|
+
export function containsSubstring(str, substr) {
|
|
39
|
+
return str.indexOf(substr) !== -1;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Check if a string starts with a prefix.
|
|
43
|
+
*
|
|
44
|
+
* @param str - The input string.
|
|
45
|
+
* @param prefix - The prefix to check.
|
|
46
|
+
* @returns True if string starts with prefix.
|
|
47
|
+
*/
|
|
48
|
+
export function startsWith(str, prefix) {
|
|
49
|
+
return str.indexOf(prefix) === 0;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Remove @ sign from the beginning of a string.
|
|
53
|
+
*
|
|
54
|
+
* @param str - The input string.
|
|
55
|
+
* @returns String with @ sign removed.
|
|
56
|
+
*/
|
|
57
|
+
export function removeAtSign(str) {
|
|
58
|
+
return str.startsWith('@') ? str.substring(1) : str;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Join array of strings with space separator.
|
|
62
|
+
*
|
|
63
|
+
* @param arr - Array of strings to join.
|
|
64
|
+
* @returns Joined string with spaces.
|
|
65
|
+
*/
|
|
66
|
+
export function joinWithSpace(arr) {
|
|
67
|
+
return arr.join(' ');
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Split string by newline character.
|
|
71
|
+
*
|
|
72
|
+
* @param str - The input string.
|
|
73
|
+
* @returns Array of strings split by newline.
|
|
74
|
+
*/
|
|
75
|
+
export function splitByNewline(str) {
|
|
76
|
+
const result = [];
|
|
77
|
+
let current = '';
|
|
78
|
+
for (let i = 0; i < str.length; i++) {
|
|
79
|
+
if (str[i] === '\n') {
|
|
80
|
+
result.push(current);
|
|
81
|
+
current = '';
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
current += str[i];
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
result.push(current);
|
|
88
|
+
return result;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Trim whitespace from string.
|
|
92
|
+
*
|
|
93
|
+
* @param str - The input string.
|
|
94
|
+
* @returns Trimmed string.
|
|
95
|
+
*/
|
|
96
|
+
export function trimString(str) {
|
|
97
|
+
let start = 0;
|
|
98
|
+
let end = str.length - 1;
|
|
99
|
+
while (start <= end &&
|
|
100
|
+
(str[start] === ' ' || str[start] === '\t' || str[start] === '\r' || str[start] === '\n')) {
|
|
101
|
+
start++;
|
|
102
|
+
}
|
|
103
|
+
while (end >= start &&
|
|
104
|
+
(str[end] === ' ' || str[end] === '\t' || str[end] === '\r' || str[end] === '\n')) {
|
|
105
|
+
end--;
|
|
106
|
+
}
|
|
107
|
+
return str.substring(start, end + 1);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Parse relation line and extract components.
|
|
111
|
+
*
|
|
112
|
+
* @param line - The line to parse.
|
|
113
|
+
* @returns Parsed relation or null if not a relation line.
|
|
114
|
+
*/
|
|
115
|
+
export function parseRelationLine(line) {
|
|
116
|
+
if (!startsWith(line, '@relation'))
|
|
117
|
+
return null;
|
|
118
|
+
const parts = splitByWhitespace(line);
|
|
119
|
+
if (parts.length < 5)
|
|
120
|
+
return null;
|
|
121
|
+
const fromParts = splitByDot(parts[1]);
|
|
122
|
+
const toParts = splitByDot(parts[2]);
|
|
123
|
+
if (fromParts.length !== 2 || toParts.length !== 2)
|
|
124
|
+
return null;
|
|
125
|
+
return {
|
|
126
|
+
fromModel: fromParts[0],
|
|
127
|
+
fromField: fromParts[1],
|
|
128
|
+
toModel: toParts[0],
|
|
129
|
+
toField: toParts[1],
|
|
130
|
+
type: parts[3],
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Split string by '-to-' delimiter.
|
|
135
|
+
*
|
|
136
|
+
* @param str - The input string.
|
|
137
|
+
* @returns Array with two parts or null if not found.
|
|
138
|
+
*/
|
|
139
|
+
export function splitByTo(str) {
|
|
140
|
+
const index = str.indexOf('-to-');
|
|
141
|
+
if (index === -1)
|
|
142
|
+
return null;
|
|
143
|
+
return [str.substring(0, index), str.substring(index + 4)];
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Remove optional suffix from string.
|
|
147
|
+
*
|
|
148
|
+
* @param str - The input string.
|
|
149
|
+
* @returns String with optional suffix removed.
|
|
150
|
+
*/
|
|
151
|
+
export function removeOptionalSuffix(str) {
|
|
152
|
+
const index = str.indexOf('-optional');
|
|
153
|
+
return index !== -1 ? str.substring(0, index) : str;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Split string by whitespace.
|
|
157
|
+
*
|
|
158
|
+
* @param str - The input string.
|
|
159
|
+
* @returns Array of strings split by whitespace.
|
|
160
|
+
*/
|
|
161
|
+
export function splitByWhitespace(str) {
|
|
162
|
+
const result = [];
|
|
163
|
+
let current = '';
|
|
164
|
+
let inWord = false;
|
|
165
|
+
for (let i = 0; i < str.length; i++) {
|
|
166
|
+
const char = str[i];
|
|
167
|
+
const isWhitespace = char === ' ' || char === '\t' || char === '\r' || char === '\n';
|
|
168
|
+
if (isWhitespace) {
|
|
169
|
+
if (inWord) {
|
|
170
|
+
result.push(current);
|
|
171
|
+
current = '';
|
|
172
|
+
inWord = false;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
current += char;
|
|
177
|
+
inWord = true;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
if (inWord) {
|
|
181
|
+
result.push(current);
|
|
182
|
+
}
|
|
183
|
+
return result;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Split string by dot character.
|
|
187
|
+
*
|
|
188
|
+
* @param str - The input string.
|
|
189
|
+
* @returns Array of strings split by dot.
|
|
190
|
+
*/
|
|
191
|
+
export function splitByDot(str) {
|
|
192
|
+
const result = [];
|
|
193
|
+
let current = '';
|
|
194
|
+
for (let i = 0; i < str.length; i++) {
|
|
195
|
+
if (str[i] === '.') {
|
|
196
|
+
result.push(current);
|
|
197
|
+
current = '';
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
current += str[i];
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
result.push(current);
|
|
204
|
+
return result;
|
|
205
|
+
}
|
|
206
|
+
/* ========================================================================== *
|
|
207
|
+
* parse
|
|
208
|
+
* ========================================================================== */
|
|
209
|
+
/**
|
|
210
|
+
* Parse field comments and extract definition line and description.
|
|
211
|
+
*
|
|
212
|
+
* @param commentLines - Raw comment lines (e.g., from source text)
|
|
213
|
+
* @param tag - The tag to look for (e.g., '@v.' or '@z.')
|
|
214
|
+
* @returns Parsed definition and description
|
|
215
|
+
*/
|
|
216
|
+
export function parseFieldComments(commentLines, tag) {
|
|
217
|
+
const cleaned = commentLines.map((line) => removeTripleSlash(line).trim()).filter(isNonEmpty);
|
|
218
|
+
// Extract object type from strictObject/looseObject tags
|
|
219
|
+
const objectTypeLine = cleaned.find((line) => containsSubstring(line, `${tag.slice(1)}strictObject`) ||
|
|
220
|
+
containsSubstring(line, `${tag.slice(1)}looseObject`));
|
|
221
|
+
const objectType = objectTypeLine && containsSubstring(objectTypeLine, 'strictObject')
|
|
222
|
+
? 'strict'
|
|
223
|
+
: objectTypeLine && containsSubstring(objectTypeLine, 'looseObject')
|
|
224
|
+
? 'loose'
|
|
225
|
+
: undefined;
|
|
226
|
+
// Extract definition (excluding strictObject/looseObject tags)
|
|
227
|
+
const definitionLine = cleaned.find((line) => startsWith(line, tag) &&
|
|
228
|
+
!containsSubstring(line, 'strictObject') &&
|
|
229
|
+
!containsSubstring(line, 'looseObject'));
|
|
230
|
+
const definition = definitionLine ? removeAtSign(definitionLine) : '';
|
|
231
|
+
const descriptionLines = cleaned.filter((line) => !(containsSubstring(line, '@z.') ||
|
|
232
|
+
containsSubstring(line, '@v.') ||
|
|
233
|
+
containsSubstring(line, '@relation.')));
|
|
234
|
+
const description = descriptionLines.length > 0 ? joinWithSpace(descriptionLines) : undefined;
|
|
235
|
+
return { definition, description, objectType };
|
|
236
|
+
}
|
|
237
|
+
/* ========================================================================== *
|
|
238
|
+
* extractFieldComments
|
|
239
|
+
* ========================================================================== */
|
|
240
|
+
/**
|
|
241
|
+
* Extract field comments from source text.
|
|
242
|
+
*
|
|
243
|
+
* @param sourceText - The source text to extract comments from.
|
|
244
|
+
* @param fieldStartPos - The position of the field in the source text.
|
|
245
|
+
* @returns An array of comment lines.
|
|
246
|
+
*/
|
|
247
|
+
export function extractFieldComments(sourceText, fieldStartPos) {
|
|
248
|
+
const beforeField = sourceText.substring(0, fieldStartPos);
|
|
249
|
+
const lines = splitByNewline(beforeField);
|
|
250
|
+
const reverseIndex = lines
|
|
251
|
+
.map((line, index) => ({ line: trimString(line), index }))
|
|
252
|
+
.reverse()
|
|
253
|
+
.reduce((acc, { line }) => {
|
|
254
|
+
if (acc.shouldStop)
|
|
255
|
+
return acc;
|
|
256
|
+
if (startsWith(line, '///')) {
|
|
257
|
+
return {
|
|
258
|
+
commentLines: [line, ...acc.commentLines],
|
|
259
|
+
shouldStop: false,
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
if (line === '') {
|
|
263
|
+
return acc;
|
|
264
|
+
}
|
|
265
|
+
return { commentLines: acc.commentLines, shouldStop: true };
|
|
266
|
+
}, { commentLines: [], shouldStop: false });
|
|
267
|
+
return reverseIndex.commentLines;
|
|
268
|
+
}
|
|
269
|
+
/* ========================================================================== *
|
|
270
|
+
* zod
|
|
271
|
+
* ========================================================================== */
|
|
272
|
+
/**
|
|
273
|
+
* @param name
|
|
274
|
+
* @returns
|
|
275
|
+
*/
|
|
276
|
+
export function infer(name) {
|
|
277
|
+
const capitalizedName = name.charAt(0).toUpperCase() + name.slice(1);
|
|
278
|
+
return `export type ${capitalizedName} = z.infer<typeof ${capitalizedName}Schema>`;
|
|
279
|
+
}
|
|
280
|
+
/* ========================================================================== *
|
|
281
|
+
* valibot
|
|
282
|
+
* ========================================================================== */
|
|
283
|
+
export function inferInput(name) {
|
|
284
|
+
const capitalizedName = name.charAt(0).toUpperCase() + name.slice(1);
|
|
285
|
+
return `export type ${capitalizedName} = v.InferInput<typeof ${capitalizedName}Schema>`;
|
|
286
|
+
}
|
|
287
|
+
/* ========================================================================== *
|
|
288
|
+
* schema
|
|
289
|
+
* ========================================================================== */
|
|
290
|
+
/**
|
|
291
|
+
* @param schema
|
|
292
|
+
* @returns
|
|
293
|
+
*/
|
|
294
|
+
export function fieldDefinitions(schema, comment) {
|
|
295
|
+
return schema.fields
|
|
296
|
+
.map(({ name, definition, description }) => {
|
|
297
|
+
const commentCode = description && comment ? `/**\n* ${description}\n*/\n` : '';
|
|
298
|
+
return `${commentCode}${name}:${definition}`;
|
|
299
|
+
})
|
|
300
|
+
.join(',\n');
|
|
301
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sizuku",
|
|
3
|
-
"
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "0.2.0",
|
|
4
5
|
"description": "Sizuku is a tool that generates validation schemas for Zod and Valibot, as well as ER diagrams, from Drizzle schemas annotated with comments.",
|
|
5
6
|
"license": "MIT",
|
|
6
7
|
"keywords": [
|
|
@@ -26,15 +27,10 @@
|
|
|
26
27
|
"dist"
|
|
27
28
|
],
|
|
28
29
|
"bin": {
|
|
29
|
-
"sizuku
|
|
30
|
-
"sizuku-valibot": "dist/generator/valibot/index.js",
|
|
31
|
-
"sizuku-mermaid-er": "dist/generator/mermaid-er/index.js"
|
|
30
|
+
"sizuku": "dist/index.js"
|
|
32
31
|
},
|
|
33
32
|
"scripts": {
|
|
34
33
|
"deps": "rm -rf node_modules && pnpm install",
|
|
35
|
-
"demo-er": "sizuku-mermaid-er db/schema.ts -o mermaid-er/ER.md",
|
|
36
|
-
"demo-z": "sizuku-zod db/schema.ts -o zod/index.ts",
|
|
37
|
-
"demo-v": "sizuku-valibot db/schema.ts -o valibot/index.ts",
|
|
38
34
|
"build": "tsc",
|
|
39
35
|
"typecheck": "tsc --noEmit",
|
|
40
36
|
"dev": "pnpm --filter sizuku-test dev",
|
|
@@ -43,14 +39,15 @@
|
|
|
43
39
|
"release": "npm pkg fix && pnpm build && npm publish"
|
|
44
40
|
},
|
|
45
41
|
"devDependencies": {
|
|
46
|
-
"@types/node": "^22.
|
|
47
|
-
"@vitest/coverage-v8": "^3.
|
|
48
|
-
"drizzle-orm": "^0.40.
|
|
42
|
+
"@types/node": "^22.15.34",
|
|
43
|
+
"@vitest/coverage-v8": "^3.2.4",
|
|
44
|
+
"drizzle-orm": "^0.40.1",
|
|
49
45
|
"valibot": "1.0.0-rc.3",
|
|
50
|
-
"vitest": "^3.
|
|
51
|
-
"zod": "^
|
|
46
|
+
"vitest": "^3.2.4",
|
|
47
|
+
"zod": "^4.0.15"
|
|
52
48
|
},
|
|
53
49
|
"dependencies": {
|
|
54
|
-
"prettier": "^3.
|
|
50
|
+
"prettier": "^3.6.2",
|
|
51
|
+
"ts-morph": "^26.0.0"
|
|
55
52
|
}
|
|
56
53
|
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export type Config = {
|
|
2
|
-
schema: {
|
|
3
|
-
name: 'PascalCase' | 'camelCase';
|
|
4
|
-
};
|
|
5
|
-
type: {
|
|
6
|
-
name: 'PascalCase' | 'camelCase';
|
|
7
|
-
export: boolean;
|
|
8
|
-
};
|
|
9
|
-
input?: string;
|
|
10
|
-
output?: string;
|
|
11
|
-
comment?: boolean;
|
|
12
|
-
};
|
|
13
|
-
export declare const DEFAULT_CONFIG: Config;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function formatCode(code: string): Promise<string>;
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.formatCode = formatCode;
|
|
4
|
-
const prettier_1 = require("prettier");
|
|
5
|
-
async function formatCode(code) {
|
|
6
|
-
return await (0, prettier_1.format)(code, {
|
|
7
|
-
parser: 'typescript',
|
|
8
|
-
printWidth: 100,
|
|
9
|
-
singleQuote: true,
|
|
10
|
-
semi: false,
|
|
11
|
-
});
|
|
12
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.generateFieldDefinitions = generateFieldDefinitions;
|
|
4
|
-
/**
|
|
5
|
-
* @function generateFieldDefinitions
|
|
6
|
-
* @param schema
|
|
7
|
-
* @returns
|
|
8
|
-
*/
|
|
9
|
-
function generateFieldDefinitions(schema, config) {
|
|
10
|
-
return schema.fields
|
|
11
|
-
.map(({ name, definition, description }) => {
|
|
12
|
-
const comment = description && config.comment ? `/**\n* ${description}\n*/\n` : '';
|
|
13
|
-
return `${comment}${name}:${definition}`;
|
|
14
|
-
})
|
|
15
|
-
.join(',\n');
|
|
16
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getCamelCaseSchemaNameHelper = getCamelCaseSchemaNameHelper;
|
|
4
|
-
const decapitalize_1 = require("../text/decapitalize");
|
|
5
|
-
/**
|
|
6
|
-
* Generates a camelCase schema name from a given schema name.
|
|
7
|
-
*
|
|
8
|
-
* @param schemaName - The original schema name.
|
|
9
|
-
* @returns The camelCase schema name.
|
|
10
|
-
*/
|
|
11
|
-
function getCamelCaseSchemaNameHelper(schemaName) {
|
|
12
|
-
const decapitalizedSchemaName = (0, decapitalize_1.decapitalize)(schemaName);
|
|
13
|
-
return `${decapitalizedSchemaName}Schema`;
|
|
14
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Generates a PascalCase schema name from a given schema name.
|
|
3
|
-
*
|
|
4
|
-
* @function getPascalCaseSchemaName
|
|
5
|
-
* @param schemaName - The original schema name.
|
|
6
|
-
* @returns The PascalCase schema name.
|
|
7
|
-
*/
|
|
8
|
-
export declare function getPascalCaseSchemaNameHelper(schemaName: string): string;
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getPascalCaseSchemaNameHelper = getPascalCaseSchemaNameHelper;
|
|
4
|
-
const capitalize_1 = require("../text/capitalize");
|
|
5
|
-
/**
|
|
6
|
-
* Generates a PascalCase schema name from a given schema name.
|
|
7
|
-
*
|
|
8
|
-
* @function getPascalCaseSchemaName
|
|
9
|
-
* @param schemaName - The original schema name.
|
|
10
|
-
* @returns The PascalCase schema name.
|
|
11
|
-
*/
|
|
12
|
-
function getPascalCaseSchemaNameHelper(schemaName) {
|
|
13
|
-
const capitalizedSchemaName = (0, capitalize_1.capitalize)(schemaName);
|
|
14
|
-
return `${capitalizedSchemaName}Schema`;
|
|
15
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { Config } from '../config';
|
|
2
|
-
/**
|
|
3
|
-
* Get the variable name helper
|
|
4
|
-
*
|
|
5
|
-
* @param name - The name of the schema
|
|
6
|
-
* @param config - The config
|
|
7
|
-
* @returns The variable name helper
|
|
8
|
-
*/
|
|
9
|
-
export declare function getVariableNameHelper(name: string, config: Config): string;
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getVariableNameHelper = getVariableNameHelper;
|
|
4
|
-
const capitalize_1 = require("../text/capitalize");
|
|
5
|
-
const decapitalize_1 = require("../text/decapitalize");
|
|
6
|
-
/**
|
|
7
|
-
* Get the variable name helper
|
|
8
|
-
*
|
|
9
|
-
* @param name - The name of the schema
|
|
10
|
-
* @param config - The config
|
|
11
|
-
* @returns The variable name helper
|
|
12
|
-
*/
|
|
13
|
-
function getVariableNameHelper(name, config) {
|
|
14
|
-
return config.type.name === 'camelCase' ? (0, decapitalize_1.decapitalize)(name) : (0, capitalize_1.capitalize)(name);
|
|
15
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { Config } from '../config';
|
|
2
|
-
/**
|
|
3
|
-
* Get the variable schema name helper
|
|
4
|
-
*
|
|
5
|
-
* @param name - The name of the schema
|
|
6
|
-
* @param config - The config
|
|
7
|
-
* @returns The variable schema name helper
|
|
8
|
-
*/
|
|
9
|
-
export declare function getVariableSchemaNameHelper(name: string, config: Config): string;
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getVariableSchemaNameHelper = getVariableSchemaNameHelper;
|
|
4
|
-
const get_camel_case_schema_name_helper_1 = require("./get-camel-case-schema-name-helper");
|
|
5
|
-
const get_pascal_case_schema_name_helper_1 = require("./get-pascal-case-schema-name-helper");
|
|
6
|
-
/**
|
|
7
|
-
* Get the variable schema name helper
|
|
8
|
-
*
|
|
9
|
-
* @param name - The name of the schema
|
|
10
|
-
* @param config - The config
|
|
11
|
-
* @returns The variable schema name helper
|
|
12
|
-
*/
|
|
13
|
-
function getVariableSchemaNameHelper(name, config) {
|
|
14
|
-
return config.schema.name === 'camelCase'
|
|
15
|
-
? (0, get_camel_case_schema_name_helper_1.getCamelCaseSchemaNameHelper)(name)
|
|
16
|
-
: (0, get_pascal_case_schema_name_helper_1.getPascalCaseSchemaNameHelper)(name);
|
|
17
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Decapitalizes the first letter of a string
|
|
3
|
-
*
|
|
4
|
-
* @function decapitalize
|
|
5
|
-
* @param str - String to decapitalize
|
|
6
|
-
* @returns String with the first letter in lowercase
|
|
7
|
-
*
|
|
8
|
-
* @example
|
|
9
|
-
* decapitalize('Posts') // Returns: 'posts'
|
|
10
|
-
* decapitalize('User') // Returns: 'user'
|
|
11
|
-
* decapitalize('Api') // Returns: 'api'
|
|
12
|
-
*
|
|
13
|
-
* @remarks
|
|
14
|
-
* - Leaves the rest of the string unchanged
|
|
15
|
-
* - Returns an empty string if the input is empty
|
|
16
|
-
*/
|
|
17
|
-
export declare function decapitalize(str: string): string;
|