Skip to content

Commit a15c8a4

Browse files
feat: add python getDef helper (#98)
1 parent 8b284dc commit a15c8a4

File tree

2 files changed

+109
-52
lines changed

2 files changed

+109
-52
lines changed

lib/__tests__/python.test.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import * as helper from "../index";
2+
3+
describe("python", () => {
4+
const { python } = helper;
5+
it("getDef", () => {
6+
const code = `
7+
a = 1
8+
9+
def b():
10+
a = 2
11+
12+
def c():
13+
a = 1
14+
`;
15+
const match = python.getDef(code, "b");
16+
if (match) {
17+
const { def, function_indentation, function_body, function_parameters } =
18+
match;
19+
expect(def).toEqual(`
20+
21+
def b():
22+
a = 2`);
23+
expect(function_indentation).toEqual(0);
24+
expect(function_body).toEqual(" a = 2");
25+
expect(function_parameters).toEqual("");
26+
}
27+
});
28+
});

lib/index.ts

Lines changed: 81 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { strip } from './strip.js';
1+
import { strip } from "./strip.js";
22

33
/**
44
* Removes every HTML-comment from the string that is provided
@@ -26,15 +26,15 @@ export function removeCssComments(str: string): string {
2626
* @returns {String}
2727
*/
2828

29-
export function removeJSComments(codeStr: string): string {
29+
export function removeJSComments(codeStr: string): string {
3030
// TODO: publish type declarations and re-enable eslint
3131
try {
3232
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
3333
return strip(codeStr);
3434
} catch (err) {
3535
return codeStr;
3636
}
37-
};
37+
}
3838

3939
/**
4040
* Removes every white-space from the string that is provided
@@ -43,7 +43,7 @@ export function removeJSComments(codeStr: string): string {
4343
*/
4444

4545
export function removeWhiteSpace(str: string): string {
46-
return str.replace(/\s/g, '');
46+
return str.replace(/\s/g, "");
4747
}
4848

4949
/**
@@ -83,9 +83,9 @@ interface ExtendedStyleDeclaration extends CSSStyleDeclaration {
8383
const getIsDeclaredAfter = (styleRule: CSSStyleRule) => (selector: string) => {
8484
const cssStyleRules = Array.from(
8585
styleRule.parentStyleSheet?.cssRules || []
86-
)?.filter(ele => ele.type === CSSRule.STYLE_RULE) as CSSStyleRule[];
86+
)?.filter((ele) => ele.type === CSSRule.STYLE_RULE) as CSSStyleRule[];
8787
const previousStyleRule = cssStyleRules.find(
88-
ele => ele?.selectorText === selector
88+
(ele) => ele?.selectorText === selector
8989
);
9090
if (!previousStyleRule) return false;
9191
const currPosition = Array.from(
@@ -97,7 +97,32 @@ const getIsDeclaredAfter = (styleRule: CSSStyleRule) => (selector: string) => {
9797
return currPosition > prevPosition;
9898
};
9999

100+
export module python {
101+
export function getDef(code: string, functionName: string) {
102+
const regex = new RegExp(
103+
`\\n(?<function_indentation>\\s*?)def\\s+${functionName}\\s*\\((?<function_parameters>[^\\)]*)\\)\\s*:\\n(?<function_body>.*?)(?=\\n\\k<function_indentation>[\\w#])`,
104+
"s"
105+
);
100106

107+
const matchedCode = regex.exec(code);
108+
if (matchedCode) {
109+
const { function_parameters, function_body, function_indentation } =
110+
matchedCode.groups;
111+
112+
const functionIndentationSansNewLine = function_indentation.replace(
113+
/\n+/,
114+
""
115+
);
116+
return {
117+
def: matchedCode[0],
118+
function_parameters,
119+
function_body,
120+
function_indentation: functionIndentationSansNewLine.length,
121+
};
122+
}
123+
return null;
124+
}
125+
}
101126

102127
export class CSSHelp {
103128
doc: Document;
@@ -107,23 +132,23 @@ export class CSSHelp {
107132
private _getStyleRules() {
108133
const styleSheet = this.getStyleSheet();
109134
return this.styleSheetToCssRulesArray(styleSheet).filter(
110-
ele => ele.type === CSSRule.STYLE_RULE
135+
(ele) => ele.type === CSSRule.STYLE_RULE
111136
) as CSSStyleRule[];
112137
}
113138

114139
getStyleDeclarations(selector: string): CSSStyleDeclaration[] {
115140
return this._getStyleRules()
116-
?.filter(ele => ele?.selectorText === selector)
117-
.map(x => x.style);
141+
?.filter((ele) => ele?.selectorText === selector)
142+
.map((x) => x.style);
118143
}
119144
getStyle(selector: string): ExtendedStyleDeclaration | null {
120145
const style = this._getStyleRules().find(
121-
ele => ele?.selectorText === selector
146+
(ele) => ele?.selectorText === selector
122147
)?.style as ExtendedStyleDeclaration | undefined;
123148
if (!style) return null;
124149
style.getPropVal = (prop: string, strip = false) => {
125150
return strip
126-
? style.getPropertyValue(prop).replace(/\s+/g, '')
151+
? style.getPropertyValue(prop).replace(/\s+/g, "")
127152
: style.getPropertyValue(prop);
128153
};
129154
return style;
@@ -132,7 +157,7 @@ export class CSSHelp {
132157
getStyleAny(selectors: string[]): ExtendedStyleDeclaration | null {
133158
for (const selector of selectors) {
134159
const style = this.getStyle(selector);
135-
160+
136161
if (style) {
137162
return style;
138163
}
@@ -142,13 +167,13 @@ export class CSSHelp {
142167
}
143168
getStyleRule(selector: string): ExtendedStyleRule | null {
144169
const styleRule = this._getStyleRules()?.find(
145-
ele => ele?.selectorText === selector
170+
(ele) => ele?.selectorText === selector
146171
);
147172
if (styleRule) {
148173
return {
149174
...styleRule,
150175
isDeclaredAfter: (selector: string) =>
151-
getIsDeclaredAfter(styleRule)(selector)
176+
getIsDeclaredAfter(styleRule)(selector),
152177
};
153178
} else {
154179
return null;
@@ -158,26 +183,26 @@ export class CSSHelp {
158183
const styleSheet = this.getStyleSheet();
159184
const cssRules = this.styleSheetToCssRulesArray(styleSheet);
160185
switch (element) {
161-
case 'media':
162-
return cssRules.filter(ele => ele.type === CSSRule.MEDIA_RULE);
163-
case 'fontface':
164-
return cssRules.filter(ele => ele.type === CSSRule.FONT_FACE_RULE);
165-
case 'import':
166-
return cssRules.filter(ele => ele.type === CSSRule.IMPORT_RULE);
167-
case 'keyframes':
168-
return cssRules.filter(ele => ele.type === CSSRule.KEYFRAMES_RULE);
186+
case "media":
187+
return cssRules.filter((ele) => ele.type === CSSRule.MEDIA_RULE);
188+
case "fontface":
189+
return cssRules.filter((ele) => ele.type === CSSRule.FONT_FACE_RULE);
190+
case "import":
191+
return cssRules.filter((ele) => ele.type === CSSRule.IMPORT_RULE);
192+
case "keyframes":
193+
return cssRules.filter((ele) => ele.type === CSSRule.KEYFRAMES_RULE);
169194
default:
170195
return cssRules;
171196
}
172197
}
173198
isPropertyUsed(property: string): boolean {
174-
return this._getStyleRules().some(ele =>
199+
return this._getStyleRules().some((ele) =>
175200
ele.style?.getPropertyValue(property)
176201
);
177202
}
178203
getRuleListsWithinMedia(mediaText: string): CSSStyleRule[] {
179-
const medias = this.getCSSRules('media') as CSSMediaRule[];
180-
const cond = medias?.find(x => x?.media?.mediaText === mediaText);
204+
const medias = this.getCSSRules("media") as CSSMediaRule[];
205+
const cond = medias?.find((x) => x?.media?.mediaText === mediaText);
181206
const cssRules = cond?.cssRules;
182207
return Array.from(cssRules || []) as CSSStyleRule[];
183208
}
@@ -189,12 +214,12 @@ export class CSSHelp {
189214

190215
// When using the styles.css tab, we add a 'fcc-injected-styles' class so we can target that. This allows users to add external scripts without them interfering
191216
const stylesDotCss: HTMLStyleElement | null = this.doc?.querySelector(
192-
'style.fcc-injected-styles'
217+
"style.fcc-injected-styles"
193218
);
194219

195220
// For steps that use <style> tags, where they don't add the above class - most* browser extensions inject styles with class/media attributes, so it filters those
196221
const styleTag: HTMLStyleElement | null = this.doc?.querySelector(
197-
'style:not([class]):not([media])'
222+
"style:not([class]):not([media])"
198223
);
199224

200225
if (link?.sheet?.cssRules?.length) {
@@ -208,41 +233,45 @@ export class CSSHelp {
208233
}
209234
}
210235
styleSheetToCssRulesArray(
211-
styleSheet: ReturnType<CSSHelp['getStyleSheet']>
236+
styleSheet: ReturnType<CSSHelp["getStyleSheet"]>
212237
): CSSRule[] {
213238
return Array.from(styleSheet?.cssRules || []);
214239
}
215240
// takes a CSS selector, returns all equivelant selectors from the current document
216241
// or an empty array if there are no matches
217242
selectorsFromSelector(selector: string): string[] {
218243
const elements = this.doc.querySelectorAll(selector);
219-
const allSelectors = Array.from(elements).map((element: Element) => {
220-
let directPath = [];
221-
let indirectPath = [];
222-
let allPaths = [];
223-
224-
while (element.parentNode) {
225-
let tag = element.tagName.toLowerCase();
226-
let siblings = Array.from(element.parentNode.children);
227-
228-
if (siblings.filter(e => e.tagName === element.tagName).length > 1) {
229-
let allSiblings = Array.from(element.parentNode.childNodes);
230-
let index = allSiblings.indexOf(element);
231-
tag += `:nth-child(${index + 1})`;
232-
}
244+
const allSelectors = Array.from(elements)
245+
.map((element: Element) => {
246+
let directPath = [];
247+
let indirectPath = [];
248+
let allPaths = [];
233249

234-
directPath.unshift(tag);
235-
indirectPath.unshift(tag);
236-
allPaths.push([directPath.join(' > '), indirectPath.join(' ')]);
237-
238-
// traverse up the DOM tree
239-
element = element.parentNode as Element;
240-
}
250+
while (element.parentNode) {
251+
let tag = element.tagName.toLowerCase();
252+
let siblings = Array.from(element.parentNode.children);
253+
254+
if (
255+
siblings.filter((e) => e.tagName === element.tagName).length > 1
256+
) {
257+
let allSiblings = Array.from(element.parentNode.childNodes);
258+
let index = allSiblings.indexOf(element);
259+
tag += `:nth-child(${index + 1})`;
260+
}
241261

242-
return allPaths.flat();
243-
}).flat();
262+
directPath.unshift(tag);
263+
indirectPath.unshift(tag);
264+
allPaths.push([directPath.join(" > "), indirectPath.join(" ")]);
265+
266+
// traverse up the DOM tree
267+
element = element.parentNode as Element;
268+
}
269+
270+
return allPaths.flat();
271+
})
272+
.flat();
244273

245274
// remove duplicates
246275
return [...new Set(allSelectors)];
247276
}
248-
}
277+
}

0 commit comments

Comments
 (0)