-
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #41 from tone-row/operate-on-edges
operate on edges
- Loading branch information
Showing
13 changed files
with
1,729 additions
and
1,415 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
import { addClassesToEdge } from "./addClassesToEdge"; | ||
|
||
describe("addClassesToEdge", () => { | ||
it("should add class to edge", () => { | ||
expect(addClassesToEdge({ line: " edge: foo", classNames: ["bar"] })).toBe(" .bar edge: foo"); | ||
}); | ||
|
||
it("should work if line starts container", () => { | ||
expect(addClassesToEdge({ line: " edge: foo {", classNames: ["bar"] })).toBe( | ||
" .bar edge: foo {", | ||
); | ||
}); | ||
|
||
it("should work when an ID is present", () => { | ||
expect(addClassesToEdge({ line: " #baz edge: foo", classNames: ["bar"] })).toBe( | ||
" #baz.bar edge: foo", | ||
); | ||
}); | ||
|
||
it("should work when edge has no label", () => { | ||
expect(addClassesToEdge({ line: " #baz: node", classNames: ["bar"] })).toBe( | ||
" #baz.bar: node", | ||
); | ||
}); | ||
|
||
it("should work when an ID is present and line starts container", () => { | ||
expect(addClassesToEdge({ line: " #baz edge: foo {", classNames: ["bar"] })).toBe( | ||
" #baz.bar edge: foo {", | ||
); | ||
}); | ||
|
||
it("should work when the line contains attributes only", () => { | ||
expect(addClassesToEdge({ line: " [foo=bar] edge: foo", classNames: ["bar"] })).toBe( | ||
' .bar[foo="bar"] edge: foo', | ||
); | ||
}); | ||
|
||
it("should work when the line contains attributes only and line starts container", () => { | ||
expect(addClassesToEdge({ line: " [foo=bar]: foo {", classNames: ["bar"] })).toBe( | ||
' .bar[foo="bar"]: foo {', | ||
); | ||
}); | ||
|
||
it("should work when the line contains attributes and an ID", () => { | ||
expect(addClassesToEdge({ line: " #baz[foo=bar] edge: foo", classNames: ["bar"] })).toBe( | ||
' #baz.bar[foo="bar"] edge: foo', | ||
); | ||
}); | ||
|
||
it("should work when the line contains attributes and an ID and line starts container", () => { | ||
expect(addClassesToEdge({ line: " #baz[foo=bar]: foo {", classNames: ["bar"] })).toBe( | ||
' #baz.bar[foo="bar"]: foo {', | ||
); | ||
}); | ||
|
||
it("should work when the line contains classes only", () => { | ||
expect(addClassesToEdge({ line: " .baz edge: foo", classNames: ["bar"] })).toBe( | ||
" .baz.bar edge: foo", | ||
); | ||
}); | ||
|
||
it("should work when the line contains classes only and line starts container", () => { | ||
expect(addClassesToEdge({ line: " .baz: foo {", classNames: ["bar"] })).toBe( | ||
" .baz.bar: foo {", | ||
); | ||
}); | ||
|
||
it("should work when the line contains classes and an ID", () => { | ||
expect(addClassesToEdge({ line: " #baz.baz edge: foo", classNames: ["bar"] })).toBe( | ||
" #baz.baz.bar edge: foo", | ||
); | ||
}); | ||
|
||
it("should work when the line contains classes and an ID and line starts container", () => { | ||
expect(addClassesToEdge({ line: " #baz.baz: foo {", classNames: ["bar"] })).toBe( | ||
" #baz.baz.bar: foo {", | ||
); | ||
}); | ||
|
||
it("should work when the line contains classes and attributes", () => { | ||
expect(addClassesToEdge({ line: " .baz[foo=bar] edge: foo", classNames: ["bar"] })).toBe( | ||
' .baz.bar[foo="bar"] edge: foo', | ||
); | ||
}); | ||
|
||
it("should work when the line contains classes and attributes and line starts container", () => { | ||
expect(addClassesToEdge({ line: " .baz[foo=bar]: foo {", classNames: ["bar"] })).toBe( | ||
' .baz.bar[foo="bar"]: foo {', | ||
); | ||
}); | ||
|
||
it("should work with multiple classes", () => { | ||
expect(addClassesToEdge({ line: " .baz.baz edge: foo", classNames: ["bar", "foo"] })).toBe( | ||
" .baz.baz.bar.foo edge: foo", | ||
); | ||
}); | ||
|
||
it("should not add class if class already present", () => { | ||
expect(addClassesToEdge({ line: " .bar edge: foo", classNames: ["bar"] })).toBe( | ||
" .bar edge: foo", | ||
); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import { featuresRe, getEdgeBreakIndex, getFeaturesIndex } from "../regexps"; | ||
|
||
import { dataToString } from "./dataToString"; | ||
import { getFeatureData } from "../getFeatureData"; | ||
|
||
export function addClassesToEdge({ line, classNames }: { line: string; classNames: string[] }) { | ||
// remove initial indent | ||
const indent = line.match(/^\s*/)?.[0] || ""; | ||
line = line.replace(/^\s*/, ""); | ||
|
||
// remove container start ("{" as last character) | ||
let containerStart = ""; | ||
if (line.endsWith(" {")) { | ||
containerStart = " {"; | ||
line = line.slice(0, -2); | ||
} | ||
|
||
// pop off edge | ||
let edge = ""; | ||
const edgeBreakIndex = getEdgeBreakIndex(line); | ||
if (edgeBreakIndex !== -1) { | ||
edge = line.slice(0, edgeBreakIndex + 1); | ||
line = line.slice(edgeBreakIndex + 1); | ||
} | ||
|
||
// separate features and label | ||
const startOfFeatures = getFeaturesIndex(edge); | ||
let features = ""; | ||
if (startOfFeatures === 0) { | ||
features = featuresRe.exec(edge)?.[0] || ""; | ||
edge = edge.slice(features.length); | ||
|
||
// reset regex | ||
featuresRe.lastIndex = 0; | ||
} | ||
|
||
if (!features) { | ||
return indent + `.${classNames.join(".")} ` + edge.trim() + line + containerStart; | ||
} | ||
|
||
// extract features from string | ||
const { classes, data, id = "" } = getFeatureData(features); | ||
|
||
let newFeatureString = " "; | ||
if (id) newFeatureString += `#${id}`; | ||
if (classes) newFeatureString += classes; | ||
let classNameString = ""; | ||
// for each class in classNames, if it's not already in classes, add it to the new class string | ||
for (const className of classNames) | ||
if (!classes.includes(className)) classNameString += `.${className}`; | ||
newFeatureString += classNameString; | ||
if (Object.keys(data).length) newFeatureString += dataToString(data); | ||
|
||
const edgeWithFeatures = [newFeatureString.trim(), edge.trim()].filter(Boolean).join(" ").trim(); | ||
|
||
return indent + edgeWithFeatures + line + containerStart; | ||
} |
4 changes: 2 additions & 2 deletions
4
...lector/src/operate/addClassToNode.test.ts → ...ctor/src/operate/addClassesToNode.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
import { removeClassesFromEdge } from "./removeClassesFromEdge"; | ||
|
||
describe("removeClassesFromEdge", () => { | ||
it("removes a classf rom an edge", () => { | ||
const result = removeClassesFromEdge({ | ||
line: ".some-class edge: my node", | ||
classNames: ["some-class"], | ||
}); | ||
expect(result).toBe("edge: my node"); | ||
}); | ||
|
||
it("doesn't alter if class isn't present", () => { | ||
const result = removeClassesFromEdge({ | ||
line: "edge: my node", | ||
classNames: ["some-class"], | ||
}); | ||
expect(result).toBe("edge: my node"); | ||
}); | ||
|
||
it("removes a class from an edge with trailing classes", () => { | ||
const result = removeClassesFromEdge({ | ||
line: ".some-class.another-class edge: my node", | ||
classNames: ["some-class"], | ||
}); | ||
expect(result).toBe(".another-class edge: my node"); | ||
}); | ||
|
||
it("removes a class from an edge with leading classes", () => { | ||
const result = removeClassesFromEdge({ | ||
line: ".some-class.another-class edge: my node", | ||
classNames: ["another-class"], | ||
}); | ||
expect(result).toBe(".some-class edge: my node"); | ||
}); | ||
|
||
it("removes a class from an edge with leading and trailing classes", () => { | ||
const result = removeClassesFromEdge({ | ||
line: ".some-class.another-class.yet-another-class edge: my node", | ||
classNames: ["another-class"], | ||
}); | ||
expect(result).toBe(".some-class.yet-another-class edge: my node"); | ||
}); | ||
|
||
it("removes a class from an edge and doesn't affect indentation", () => { | ||
const result = removeClassesFromEdge({ | ||
line: " .some-class edge: my node", | ||
classNames: ["some-class"], | ||
}); | ||
expect(result).toBe(" edge: my node"); | ||
}); | ||
|
||
it("removes a class from an edge without affecting the node", () => { | ||
const result = removeClassesFromEdge({ | ||
line: " .some-class edge: my node .some-class", | ||
classNames: ["some-class"], | ||
}); | ||
expect(result).toBe(" edge: my node .some-class"); | ||
}); | ||
|
||
it("can remove multiple classes at once", () => { | ||
const result = removeClassesFromEdge({ | ||
line: ".some-class.another-class edge: my node", | ||
classNames: ["some-class", "another-class"], | ||
}); | ||
expect(result).toBe("edge: my node"); | ||
}); | ||
|
||
it("can remove class when no edge label", () => { | ||
const result = removeClassesFromEdge({ | ||
line: " .some-class: my node", | ||
classNames: ["some-class"], | ||
}); | ||
expect(result).toBe(" my node"); | ||
}); | ||
|
||
it("can remove edge class when starting container line", () => { | ||
const result = removeClassesFromEdge({ | ||
line: " .some-class edge: container {", | ||
classNames: ["some-class"], | ||
}); | ||
expect(result).toBe(" edge: container {"); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import { getEdgeBreakIndex } from "../regexps"; | ||
|
||
export function removeClassesFromEdge({ | ||
line, | ||
classNames, | ||
}: { | ||
/** The line text */ | ||
line: string; | ||
/** Array of string *without* the dot (.) */ | ||
classNames: string[]; | ||
}) { | ||
// remove initial indent and store | ||
const indent = line.match(/^\s*/)?.[0]; | ||
line = line.replace(/^\s*/, ""); | ||
|
||
// remove container start ("{" as last character) | ||
let containerStart = ""; | ||
if (line.endsWith(" {")) { | ||
containerStart = " {"; | ||
line = line.slice(0, -2); | ||
} | ||
|
||
// check for unescaped colon that's not at the start of the line | ||
// if it exists, we're dealing with an edge | ||
let edge = ""; | ||
const edgeBreakIndex = getEdgeBreakIndex(line); | ||
if (edgeBreakIndex !== -1) { | ||
edge = line.slice(0, edgeBreakIndex + 1); | ||
line = line.slice(edgeBreakIndex + 1); | ||
} | ||
|
||
// remove class names from edge | ||
for (const className of classNames) { | ||
edge = edge.replace(new RegExp(`\.${className}`), ""); | ||
} | ||
|
||
// remove leading whitespace before beginning of line if it exists | ||
edge = edge.replace(/^\s*/, ""); | ||
|
||
// if the edge is empty and the line begins with a colon, | ||
if (edge === "" && line.startsWith(":")) { | ||
// remove the colon and whitespace | ||
line = line.replace(/^[::]\s*/, ""); | ||
} | ||
|
||
return indent + edge + line + containerStart; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.