Skip to content

Commit

Permalink
webpage and other fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
chwoerz committed Dec 17, 2024
1 parent a73af68 commit b81f42b
Show file tree
Hide file tree
Showing 29 changed files with 413 additions and 311 deletions.
106 changes: 68 additions & 38 deletions agnostic/agnostic.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
import { Node, Project, ScriptTarget, ts, FunctionDeclaration, IfStatement, Statement } from "ts-morph";
import {
Block,
FunctionDeclaration,
IfStatement,
Node,
Project,
ScriptTarget,
Statement,
ts
} from "ts-morph";
import ModuleResolutionKind = ts.ModuleResolutionKind;
import SyntaxKind = ts.SyntaxKind;

Expand Down Expand Up @@ -79,15 +88,17 @@ export function getAllTypeConditionalDeclarations(input: string): string[] {

return allTypeAliases.map((alias) => alias.getText());
}

function unwrapParenthesizedType(node: Node | undefined): Node {
if(node === undefined) {
if (node === undefined) {
throw new Error("Node is undefined");
}
if (node?.isKind(SyntaxKind.ParenthesizedType)) {
return unwrapParenthesizedType(node.getFirstChildByKind(SyntaxKind.ConditionalType));
}
return node;
}

function traverseTernary(node: Node | undefined, store: string[]) {
node = unwrapParenthesizedType(node);
if (node.isKind(SyntaxKind.ConditionalType)) {
Expand Down Expand Up @@ -180,20 +191,20 @@ function replaceIfBlockValuesWithString(code: string) {
const fnName = line.substring(fnIndexStart, fnIndexEnd).trim();
const fixedLine = `function ${fnName}(${fixeds.map((f) => f.fixedLine).join(", ")}) {`;
workingLines.push(fixedLine);
replacements.push(...fixeds.map((f) => ({ index: f.fixedLine, backReplace: f.condition })));
replacements.push(...fixeds.map((f) => ({index: f.fixedLine, backReplace: f.condition})));
} else if (matched?.length) {
const fixedLine = replaceConditionWithFixed(line, matched[0], replaceValue);
workingLines.push(fixedLine.fixedLine);
replacements.push({ index: replaceValue, backReplace: fixedLine.condition });
replacements.push({index: replaceValue, backReplace: fixedLine.condition});
} else if (line.match(/^\s*return/)) {
const fixedLine = replaceReturnWithFixed(line, replaceValue);
workingLines.push(fixedLine.fixedLine);
replacements.push({ index: replaceValue, backReplace: fixedLine.condition });
replacements.push({index: replaceValue, backReplace: fixedLine.condition});
} else {
workingLines.push(line);
}
}
return { workingLines, replacements };
return {workingLines, replacements};
}

function replaceArgumentsWithFixed(args: string): {
Expand All @@ -202,7 +213,7 @@ function replaceArgumentsWithFixed(args: string): {
}[] {
const splitArgs = args.split(",");
return splitArgs.map((arg, i) => {
return { condition: arg, fixedLine: `replace${i}` };
return {condition: arg, fixedLine: `replace${i}`};
});
}

Expand All @@ -217,7 +228,7 @@ function replaceReturnWithFixed(
const conditionStartIndex = line.indexOf(returnStr);
const endIndex = line.endsWith(";") ? line.length - 1 : line.length;
const condition = line.substring(conditionStartIndex + returnStr.length, endIndex);
return { condition, fixedLine: line.replace(condition, fixed) };
return {condition, fixedLine: line.replace(condition, fixed)};
}

function replaceConditionWithFixed(
Expand All @@ -231,7 +242,7 @@ function replaceConditionWithFixed(
const conditionStartIndex = line.indexOf(prefix);
const conditionEndIndex = line.lastIndexOf(")");
const condition = line.substring(conditionStartIndex + prefix.length, conditionEndIndex);
return { condition, fixedLine: line.replace(condition, fixed) };
return {condition, fixedLine: line.replace(condition, fixed)};
}

function transformFnToTernary(func: FunctionDeclaration) {
Expand All @@ -250,44 +261,65 @@ function transformFnToTernary(func: FunctionDeclaration) {
return `type ${fnName}<${fnParameters}> =\n ${ternaryExpr};`;
}

function handleBlock(block: Block, indent: number) {
const innerStmts = block.getStatements();
const message = "There needs to be a EXACTLY ONE return inside of if, else if or else blocks. NOTHING else.\nLine: " +
block.getStartLineNumber();
if (innerStmts.length !== 1) {
throw new Error(message);
}
const onlyStatement = innerStmts[0];
if (onlyStatement.isKind(SyntaxKind.ReturnStatement)) {
const returnExpr = onlyStatement.getExpression();
if (returnExpr) {
return returnExpr.getText();
}
throw new Error(message);
} else if (onlyStatement.isKind(SyntaxKind.IfStatement)) {
// Nested if
return transformIfStatementToTernary(onlyStatement, indent + 1);
} else {
// If there's more complexity here, you'd need more logic.
throw new Error("Expected a single return or a nested if in the block. \nLine: " + block.getEndLineNumber());
}
}

/**
* Extracts a return expression from a block that must contain a single return statement.
* If the block contains nested ifs, we will process them recursively.
*/
function getBlockReturnExpression(block: Statement, indent: number): string {
if (block.isKind(SyntaxKind.Block)) {
const innerStmts = block.getStatements();
if (innerStmts.length === 1) {
const singleStmt = innerStmts[0];
if (singleStmt.isKind(SyntaxKind.ReturnStatement)) {
const returnExpr = singleStmt.getExpression();
if (!returnExpr) {
throw new Error(
"There needs to be a EXACTLY ONE return inside of if, else if or else blocks. NOTHING else.\nLine: " +
singleStmt.getStartLineNumber()
);
}
return returnExpr.getText();
} else if (singleStmt.isKind(SyntaxKind.IfStatement)) {
// Nested if
return transformIfStatementToTernary(singleStmt, indent + 1);
}
}
// If there's more complexity here, you'd need more logic.
throw new Error("Expected a single return or a nested if in the block. \nLine: " + block.getEndLineNumber());
return handleBlock(block, indent);
} else if (block.isKind(SyntaxKind.ReturnStatement)) {
// Direct return, no block
const returnExpr = block.getExpression();
return returnExpr ? returnExpr.getText() : "undefined";
const returnExpr = block.getExpression()?.getText();
return returnExpr?.length ? returnExpr : "never";
} else if (block.isKind(SyntaxKind.IfStatement)) {
// Direct nested if without a block
return transformIfStatementToTernary(block, indent + 1);
} else if (block.getChildren().length) {
throw new Error(
"There needs to be a EXACTLY ONE return inside of if, else if or else blocks. NOTHING else.\nLine: " +
block.getStartLineNumber()
);
}
return 'never';
}

throw new Error(
"This block structure is not supported. Only if, else if or else blocks with exactly one return in there are supported\n Line: " +
block.getEndLineNumber()
);
function noElseBlock(ifStmt: IfStatement, indentation: string, thenExpr: string) {
const conditionText = ifStmt.getExpression().getText();
const noSibling = !ifStmt.getNextSiblings().length;
const oneNextSibling = ifStmt.getNextSiblings().length === 1;
const isSiblingReturn = ifStmt.getNextSibling()?.isKind(SyntaxKind.ReturnStatement);
if (oneNextSibling && isSiblingReturn) {
const returnExpr = ifStmt.getNextSibling()!.asKindOrThrow(SyntaxKind.ReturnStatement).getExpression();
return `${conditionText}\n${indentation}? ${thenExpr}\n${indentation}: ${returnExpr?.getText()}`;
} else if (noSibling) {
return `${conditionText}\n${indentation}? ${thenExpr}\n${indentation}: never`;
} else {
throw new Error("There needs to be a EXACTLY ONE return inside of \n//if, else if or else blocks. NOTHING else.\n//Line: " + ifStmt.getEndLineNumber());
}
}

/**
Expand All @@ -300,11 +332,9 @@ function transformIfStatementToTernary(ifStmt: IfStatement, indent: number): str
const elseBranch = ifStmt.getElseStatement();
const thenExpr = getBlockReturnExpression(thenBranch, indent);

// If there is no else, we might handle differently, but here we assume full if-else chains.

if (!elseBranch) {
// If no else branch, it's just condition ? thenExpr : undefined (or some fallback)
// But usually you have a full chain. If needed, handle no-else case here.
throw new Error("No else branch found. This is not supported. Line: " + ifStmt.getStartLineNumber());
return noElseBlock(ifStmt, indentation, thenExpr);
}
let elseExpr: string;
if (elseBranch.isKind(SyntaxKind.IfStatement)) {
Expand Down
1 change: 1 addition & 0 deletions copy-down.sh
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
cp README.md ./extension/README.md
cp ./agnostic/agnostic.ts ./extension/src/agnostic.ts
cp ./agnostic/agnostic.ts ./page/src/agnostic.ts
cp LICENSE ./extension/LICENSE

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file added docs/assets/favicon-DJ6lD6qs.ico
Binary file not shown.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

322 changes: 164 additions & 158 deletions docs/assets/index-CtY07X99.js → docs/assets/index-QL_uhewY.js

Large diffs are not rendered by default.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Editor Layout</title>
<script type="module" crossorigin src="/type-buddy/assets/index-CtY07X99.js"></script>
<title>Type Buddy 🤝</title>
<link rel="icon" type="image/x-icon" href="/type-buddy/assets/favicon-DJ6lD6qs.ico">
<script type="module" crossorigin src="/type-buddy/assets/index-QL_uhewY.js"></script>
<link rel="stylesheet" crossorigin href="/type-buddy/assets/index--qxT1i_6.css">
</head>
<body>
Expand Down
6 changes: 1 addition & 5 deletions extension/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
# Change Log

All notable changes to the "type-buddy" extension will be documented in this file.

Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file.

## [Unreleased]
## [0.0.1]

- Initial release
21 changes: 21 additions & 0 deletions extension/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2024 Typed Rocks

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Binary file added extension/imgs/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
"displayName": "Type Buddy",
"description": "A simple extension to help you understand TypeScript types",
"version": "0.0.1",
"publisher": "chwoerz",
"engines": {
"vscode": "^1.85.0"
},
"icon": "imgs/typebuddy-icon.png",
"icon": "imgs/icon.png",
"categories": [
"Debuggers"
],
Expand Down
Loading

0 comments on commit b81f42b

Please sign in to comment.