Skip to content

Commit

Permalink
feat: add getBlock python helper (#104)
Browse files Browse the repository at this point in the history
  • Loading branch information
ShaunSHamilton authored Dec 11, 2023
1 parent 0d7e0a2 commit c67c0cc
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 0 deletions.
55 changes: 55 additions & 0 deletions lib/__tests__/python.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,59 @@ def c():
expect(function_parameters).toEqual("d, e");
}
});

it("getBlock", () => {
const code = `
a = 1
if a == 1:
a = 2
b = 3
if b == 3:
a = 4
for i in range(10):
a = 1
`;
const matches = [
python.getBlock(code, "if a == 1"),
python.getBlock(code, /if +\w+ *== *\d+/),
// eslint-disable-next-line prefer-regex-literals
python.getBlock(code, new RegExp("if +\\w+ *== *\\d+")),
];
for (const match of matches) {
expect(match).not.toBeNull();
if (match) {
// eslint-disable-next-line camelcase
const { block_indentation, block_body, block_condition } = match;
expect(block_condition).toEqual("if a == 1");
expect(block_indentation).toEqual(0);
expect(block_body).toEqual(
` a = 2
b = 3
if b == 3:
a = 4
`
);
}
}

const matches2 = [
python.getBlock(code, "for i in range(10)"),
python.getBlock(code, /for +\w+ +in +range\(\d+\)/),
// eslint-disable-next-line prefer-regex-literals
python.getBlock(code, new RegExp("for +\\w+ +in +range\\(\\d+\\)")),
];
for (const match of matches2) {
expect(match).not.toBeNull();
if (match) {
// eslint-disable-next-line camelcase
const { block_indentation, block_body, block_condition } = match;
expect(block_condition).toEqual("for i in range(10)");
expect(block_indentation).toEqual(0);
expect(block_body).toEqual(` a = 1
`);
}
}
});
});
36 changes: 36 additions & 0 deletions lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,42 @@ export module python {

return null;
}

/**
* Gets a Python block of code matching the `blockPattern`
* @param code - Code string to search
* @param blockPattern - String or regular expression to match on the block condition
*
* **Note:** A string `blockPattern` will be escaped to prevent special characters from being treated as regular expression syntax.
*/
export function getBlock(code: string, blockPattern: string | RegExp) {
const escapedBlockPattern =
blockPattern instanceof RegExp
? blockPattern.source
: blockPattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");

const regex = new RegExp(
`\\n(?<block_indentation> *?)(?<block_condition>${escapedBlockPattern})\\s*:\\n(?<block_body>.*?)(?=\\n\\k<block_indentation>[\\w#]|$)`,
"s"
);

const matchedCode = regex.exec(code);
if (matchedCode) {
/* eslint-disable camelcase */
const { block_body, block_indentation, block_condition } =
matchedCode.groups;

const blockIndentationSansNewLine = block_indentation.replace(/\n+/g, "");
return {
block_body,
block_condition,
block_indentation: blockIndentationSansNewLine.length,
};
/* eslint-enable camelcase */
}

return null;
}
}

export class CSSHelp {
Expand Down

0 comments on commit c67c0cc

Please sign in to comment.