Skip to content

Commit e4ceaa3

Browse files
authored
Merge pull request #120 from code0-tech/feat/fixing-blocking-and-null-state
Fixing blocking and null state
2 parents cf25f5c + 6e2ca2a commit e4ceaa3

3 files changed

Lines changed: 75 additions & 25 deletions

File tree

src/schema/getSignatureSchema.ts

Lines changed: 62 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ export const getSignatureSchema = (
9393
)
9494

9595
// Identify parameter dependencies based on type parameters
96-
const funktionDependencies = getParameterDependencies(funktion!)
96+
const funktionDependencies = getParameterDependencies(funktion!, nodeParameterTypes)
9797

9898
// Generate schema for each parameter
9999
return generateNodeSchemas(
@@ -203,30 +203,57 @@ const extractFunctionParameterTypes = (
203203
/**
204204
* Identifies parameter dependencies based on shared type parameters.
205205
* Determines which parameters depend on type parameters declared in other parameters.
206+
* If an argument is explicitly provided (not null/undefined), it is not blocked.
206207
*
207-
* @param node - The function declaration to analyze
208+
* @param funktion - The function declaration to analyze
209+
* @param nodeParameterTypes
208210
* @returns Array of ParameterDependency objects
209211
*/
210-
const getParameterDependencies = (node: ts.FunctionDeclaration): ParameterDependency[] => {
211-
// Extract all type parameter names from the function
212-
const typeParamNames = node.typeParameters?.map((tp) => tp.name.getText()) || []
212+
const getParameterDependencies = (
213+
funktion: ts.FunctionDeclaration,
214+
nodeParameterTypes: ts.Type[] | undefined
215+
): ParameterDependency[] => {
216+
const typeParamNames = funktion.typeParameters?.map((tp) => tp.name.getText()) || []
213217
const usage: Record<string, number[]> = {}
214218

215219
// Track which parameters use each type parameter
216-
node.parameters.forEach((p, i) => {
217-
const typeText = p.type?.getText() || ""
218-
typeParamNames.forEach((typeParam) => {
219-
if (typeText.includes(typeParam)) {
220-
if (!usage[typeParam]) {
221-
usage[typeParam] = []
220+
funktion.parameters.forEach((p, i) => {
221+
if (!p.type) return
222+
223+
// Ein Set, um Duplikate pro Parameter zu vermeiden (falls 'A' mehrfach im selben Param-Typ vorkommt)
224+
const foundInParameter = new Set<string>()
225+
226+
// Wir laufen rekursiv durch den Typ-Knoten des Parameters
227+
p.type.forEachChild(function visitor(child) {
228+
// Sucht nach expliziten Typ-Referenzen (z.B. die Typen in den <...> oder der Typ selbst)
229+
if (ts.isTypeReferenceNode(child) && ts.isIdentifier(child.typeName)) {
230+
const typeName = child.typeName.text
231+
if (typeParamNames.includes(typeName)) {
232+
foundInParameter.add(typeName)
233+
}
234+
}
235+
// Falls der Typ selbst nur der Typparameter ist (z.B. p.type ist direkt ein TypeReferenceNode)
236+
if (ts.isTypeReferenceNode(p.type!) && ts.isIdentifier(p.type.typeName)) {
237+
const directTypeName = p.type.typeName.text
238+
if (typeParamNames.includes(directTypeName)) {
239+
foundInParameter.add(directTypeName)
222240
}
223-
usage[typeParam].push(i)
224241
}
242+
243+
child.forEachChild(visitor)
244+
})
245+
246+
// Gefundene Abhängigkeiten für diesen Parameter registrieren
247+
foundInParameter.forEach((typeParam) => {
248+
if (!usage[typeParam]) {
249+
usage[typeParam] = []
250+
}
251+
usage[typeParam].push(i)
225252
})
226253
})
227254

228-
// Extract dependencies: type params used by multiple parameters
229-
return Object.values(usage)
255+
// Extract raw dependencies based on type definition
256+
const rawDependencies = Object.values(usage)
230257
.filter((indices) => indices.length > 1)
231258
.map(([firstIndex, ...otherIndices]) =>
232259
otherIndices.map((depIndex) => ({
@@ -235,8 +262,28 @@ const getParameterDependencies = (node: ts.FunctionDeclaration): ParameterDepend
235262
})),
236263
)
237264
.flat()
238-
}
239265

266+
// Wenn wir keine Typen vom Checker haben, bleiben wir beim Standard
267+
if (!nodeParameterTypes) {
268+
return rawDependencies
269+
}
270+
271+
// Filter heraus, was durch echte Werte (nicht null/undefined) bereits aufgelöst ist
272+
return rawDependencies.filter((dep) => {
273+
const resolvedType = nodeParameterTypes[dep.parameterIndex]
274+
275+
// Falls aus irgendeinem Grund kein Typ ermittelt werden konnte -> blocked lassen
276+
if (!resolvedType) return true
277+
278+
// Prüfen, ob der Typ null oder undefined ist
279+
const isNull = (resolvedType.flags & ts.TypeFlags.Null) !== 0
280+
const isUndefined = (resolvedType.flags & ts.TypeFlags.Undefined) !== 0
281+
282+
// Wenn es null oder undefined IST, bleibt es blocked (true)
283+
// Wenn es ein echter Wert ist, fliegt die Dependency raus (false)
284+
return isNull || isUndefined
285+
})
286+
}
240287
/**
241288
* Generates node schemas for all parameters.
242289
* Creates schema objects for each parameter with their dependencies.

src/util/schema.util.ts

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -161,15 +161,15 @@ export const getSchema = (
161161
],
162162
} : {};
163163

164-
// Strip undefined from unions (e.g. string | undefined → string).
164+
// Strip undefined and null from unions (e.g. string | undefined | null → string).
165165
// Suggestions are collected above from the original type (preserving aliasSymbol literals),
166166
// the base schema is determined from the stripped type, then both are merged.
167167
if (parameterType.isUnion()) {
168-
const nonUndefined = parameterType.types.filter(
169-
(t) => (t.flags & ts.TypeFlags.Undefined) === 0
168+
const nonNullish = parameterType.types.filter(
169+
(t) => (t.flags & (ts.TypeFlags.Undefined | ts.TypeFlags.Null)) === 0
170170
)
171-
if (nonUndefined.length === 1) {
172-
const baseSchema = getSchema(checker, node, nonUndefined[0], functionDeclarations, functions, false)
171+
if (nonNullish.length === 1) {
172+
const baseSchema = getSchema(checker, node, nonNullish[0], functionDeclarations, functions, false)
173173
return {...baseSchema, ...combinedSuggestions}
174174
}
175175
}
@@ -240,13 +240,13 @@ export const getSchema = (
240240
(property.flags & ts.SymbolFlags.Optional) !== 0 ||
241241
(propertyType.isUnion() &&
242242
propertyType.types.some(
243-
(t) => (t.flags & ts.TypeFlags.Undefined) !== 0
243+
(t) => (t.flags & (ts.TypeFlags.Undefined | ts.TypeFlags.Null)) !== 0
244244
));
245245

246-
// Filter out undefined type from union types
246+
// Filter out undefined and null types from union types
247247
const propertyTypes = propertyType.isUnion()
248248
? propertyType.types.filter(
249-
(t) => (t.flags & ts.TypeFlags.Undefined) === 0
249+
(t) => (t.flags & (ts.TypeFlags.Undefined | ts.TypeFlags.Null)) === 0
250250
)
251251
: [propertyType];
252252

@@ -358,7 +358,10 @@ function isStringOrNumberLiteral(type: ts.Type): boolean {
358358
*/
359359
function isPrimitiveLiteralUnion(type: ts.Type): boolean {
360360
if (!type.isUnion()) return false;
361-
return type.types.every(isPrimitive);
361+
const nonNullish = type.types.filter(
362+
(t) => (t.flags & (ts.TypeFlags.Undefined | ts.TypeFlags.Null)) === 0
363+
);
364+
return nonNullish.length > 0 && nonNullish.every(isPrimitive);
362365
}
363366

364367
/**

src/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ export function generateFlowSourceCode(
134134
return `/* @pos ${id} ${index} */ ${refCode}`;
135135
}
136136
if (val.__typename === "LiteralValue") {
137-
const jsonString = stringify(val?.value)
137+
const jsonString = val?.value !== null && val?.value !== undefined ? stringify(val?.value) : undefined
138138
return `/* @pos ${id} ${index} */ ${jsonString}`;
139139
}
140140
if (val.__typename === "SubFlowValue") {

0 commit comments

Comments
 (0)