refactor: improve type safety · unjs/untyped@7f51a8a · GitHub
Skip to content

Commit 7f51a8a

Browse files
committed
refactor: improve type safety
1 parent 88c2803 commit 7f51a8a

4 files changed

Lines changed: 65 additions & 40 deletions

File tree

src/generator/dts.ts

Lines changed: 7 additions & 7 deletions

src/loader/babel.ts

Lines changed: 46 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010

1111
import { version } from "../../package.json";
1212

13-
type GetCodeFn = (loc: t.SourceLocation) => string;
13+
type GetCodeFn = (loc: t.SourceLocation | null | undefined) => string;
1414

1515
const babelPluginUntyped: PluginItem = function (
1616
api: ConfigAPI,
@@ -62,15 +62,18 @@ const babelPluginUntyped: PluginItem = function (
6262
if (schemaProp && "value" in schemaProp) {
6363
if (schemaProp.value.type === "ObjectExpression") {
6464
// Object has $schema
65-
schemaProp.value.properties.push(...astify(schema).properties);
65+
schemaProp.value.properties.push(
66+
...(astify(schema) as t.ObjectExpression).properties,
67+
);
6668
} else {
6769
// Object has $schema which is not an object
6870
// SKIP
6971
}
7072
} else {
7173
// Object has not $schema
7274
valueNode.properties.unshift(
73-
...astify({ $schema: schema }).properties,
75+
...(astify({ $schema: schema }) as t.ObjectExpression)
76+
.properties,
7477
);
7578
}
7679
} else {
@@ -95,7 +98,7 @@ const babelPluginUntyped: PluginItem = function (
9598
// Experimental functions meta support
9699
if (
97100
!options.experimentalFunctions &&
98-
!schema.tags.includes("@untyped")
101+
!schema.tags?.includes("@untyped")
99102
) {
100103
return;
101104
}
@@ -110,10 +113,13 @@ const babelPluginUntyped: PluginItem = function (
110113

111114
const _getLines = cachedFn(() => this.file.code.split("\n"));
112115
const getCode: GetCodeFn = (loc) => {
116+
if (!loc) {
117+
return "";
118+
}
113119
const _lines = _getLines();
114120
return (
115121
_lines[loc.start.line - 1]
116-
.slice(loc.start.column, loc.end.column)
122+
?.slice(loc.start.column, loc.end.column)
117123
.trim() || ""
118124
);
119125
};
@@ -143,7 +149,7 @@ const babelPluginUntyped: PluginItem = function (
143149
arg,
144150
mergedTypes(
145151
arg,
146-
inferAnnotationType(lparam.typeAnnotation, getCode),
152+
inferAnnotationType(lparam.typeAnnotation!, getCode)!,
147153
),
148154
);
149155
}
@@ -197,7 +203,7 @@ const babelPluginUntyped: PluginItem = function (
197203
p.replaceWith(
198204
t.variableDeclaration("const", [
199205
t.variableDeclarator(
200-
t.identifier(p.node.id.name),
206+
t.identifier(p.node.id!.name),
201207
astify({ $schema: schema }),
202208
),
203209
]),
@@ -220,7 +226,7 @@ function containsIncompleteCodeblock(line = "") {
220226
function clumpLines(lines: string[], delimiters = [" "], separator = " ") {
221227
const clumps: string[] = [];
222228
while (lines.length > 0) {
223-
const line = lines.shift();
229+
const line = lines.shift()!;
224230
if (
225231
(line && !delimiters.includes(line[0]) && clumps.at(-1)) ||
226232
containsIncompleteCodeblock(clumps.at(-1))
@@ -281,21 +287,25 @@ function parseJSDocs(input: string | string[]): Schema {
281287
Object.assign(schema, getTypeDescriptor(type));
282288
for (const typedef in typedefs) {
283289
schema.markdownType = type;
284-
schema.tsType = schema.tsType.replace(
285-
new RegExp(typedefs[typedef], "g"),
286-
typedef,
287-
);
290+
if (schema.tsType) {
291+
schema.tsType = schema.tsType.replace(
292+
new RegExp(typedefs[typedef], "g"),
293+
typedef,
294+
);
295+
}
288296
}
289297
continue;
290298
}
291-
schema.tags.push(tag.trim());
299+
schema.tags!.push(tag.trim());
292300
}
293301
}
294302

295303
return schema;
296304
}
297305

298-
function astify(val) {
306+
function astify(
307+
val: unknown,
308+
): t.Literal | t.Identifier | t.ArrayExpression | t.ObjectExpression {
299309
if (typeof val === "string") {
300310
return t.stringLiteral(val);
301311
}
@@ -316,8 +326,17 @@ function astify(val) {
316326
}
317327
return t.objectExpression(
318328
Object.getOwnPropertyNames(val)
319-
.filter((key) => val[key] !== undefined && val[key] !== null)
320-
.map((key) => t.objectProperty(t.identifier(key), astify(val[key]))),
329+
.filter(
330+
(key) =>
331+
val[key as keyof typeof val] !== undefined &&
332+
val[key as keyof typeof val] !== null,
333+
)
334+
.map((key) =>
335+
t.objectProperty(
336+
t.identifier(key),
337+
astify(val[key as keyof typeof val]),
338+
),
339+
),
321340
);
322341
}
323342

@@ -336,7 +355,7 @@ const AST_JSTYPE_MAP: Partial<Record<t.Expression["type"], JSType | "RegExp">> =
336355

337356
function inferArgType(e: t.Expression, getCode: GetCodeFn): TypeDescriptor {
338357
if (AST_JSTYPE_MAP[e.type]) {
339-
return getTypeDescriptor(AST_JSTYPE_MAP[e.type]);
358+
return getTypeDescriptor(AST_JSTYPE_MAP[e.type]!);
340359
}
341360
if (e.type === "AssignmentExpression") {
342361
return inferArgType(e.right, getCode);
@@ -351,7 +370,7 @@ function inferArgType(e: t.Expression, getCode: GetCodeFn): TypeDescriptor {
351370
return {
352371
type: "array",
353372
items: {
354-
type: normalizeTypes(itemTypes),
373+
type: normalizeTypes(itemTypes as JSType[]),
355374
},
356375
};
357376
}
@@ -361,22 +380,23 @@ function inferArgType(e: t.Expression, getCode: GetCodeFn): TypeDescriptor {
361380
function inferAnnotationType(
362381
ann: t.Identifier["typeAnnotation"],
363382
getCode: GetCodeFn,
364-
): TypeDescriptor | null {
365-
if (ann.type !== "TSTypeAnnotation") {
366-
return null;
383+
): TypeDescriptor | undefined {
384+
if (ann?.type !== "TSTypeAnnotation") {
385+
return undefined;
367386
}
368387
return inferTSType(ann.typeAnnotation, getCode);
369388
}
370389

371-
function inferTSType(
372-
tsType: t.TSType,
373-
getCode: GetCodeFn,
374-
): TypeDescriptor | null {
390+
function inferTSType(tsType: t.TSType, getCode: GetCodeFn): TypeDescriptor {
375391
if (tsType.type === "TSParenthesizedType") {
376392
return inferTSType(tsType.typeAnnotation, getCode);
377393
}
378394
if (tsType.type === "TSTypeReference") {
379-
if ("name" in tsType.typeName && tsType.typeName.name === "Array") {
395+
if (
396+
tsType.typeParameters &&
397+
"name" in tsType.typeName &&
398+
tsType.typeName.name === "Array"
399+
) {
380400
return {
381401
type: "array",
382402
items: inferTSType(tsType.typeParameters.params[0], getCode),

src/schema.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export async function resolveSchema(
3232
root: obj,
3333
defaults,
3434
resolveCache: {},
35-
ignoreDefaults: options.ignoreDefaults,
35+
ignoreDefaults: !!options.ignoreDefaults,
3636
});
3737
// TODO: Create meta-schema fror superset of Schema interface
3838
// schema.$schema = 'http://json-schema.org/schema#'

src/utils.ts

Lines changed: 11 additions & 6 deletions

0 commit comments

Comments
 (0)