New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

textlint-util-to-string

Package Overview
Dependencies
Maintainers
3
Versions
18
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

textlint-util-to-string - npm Package Compare versions

Comparing version 3.2.0 to 3.3.0

dist/replacer.d.ts

14

dist/StringSource.d.ts
import type { TxtNode, TxtParentNode } from "@textlint/ast-node-types";
import { SourcePosition } from "structured-source";
import type { Node as UnistNode } from "unist";
import { emptyValue, maskValue, StringSourceReplacerCommand } from "./replacer";
export type StringSourceOptions = {
replacer?: ({ node, parent }: {
node: TxtNode | UnistNode;
parent?: TxtParentNode;
maskValue: typeof maskValue;
emptyValue: typeof emptyValue;
}) => StringSourceReplacerCommand | undefined;
};
export default class StringSource {

@@ -10,3 +19,3 @@ private rootNode;

private tokenMaps;
constructor(node: TxtParentNode);
constructor(node: TxtParentNode, options?: StringSourceOptions);
toString(): string;

@@ -69,8 +78,9 @@ /**

* does not expose plain-text fields, `toString` will
* recursively mapping
* recursively map
*
* @param {Node} node - Node to transform to a string.
* @param {Node} [parent] - Parent Node of the `node`.
* @param options
*/
private _stringify;
}

4

package.json
{
"name": "textlint-util-to-string",
"version": "3.2.0",
"version": "3.3.0",
"description": "textlint utility that convert Paragraph Node to text with SourceMap.",

@@ -47,3 +47,3 @@ "homepage": "https://github.com/textlint/textlint-util-to-string",

"lint-staged": "^13.1.0",
"markdown-to-ast": "^6.0.3",
"@textlint/markdown-to-ast": "^13.2.0",
"microbundle": "^0.15.1",

@@ -50,0 +50,0 @@ "mocha": "^10.2.0",

# textlint-util-to-string [![Actions Status: test](https://github.com/textlint/textlint-util-to-string/workflows/test/badge.svg)](https://github.com/textlint/textlint-util-to-string/actions?query=workflow%3A"test")
Convert `Paragraph` Node to plain text with SourceMap.
It means that you can get original position from plain text.
SourceMap mean that could revert `position` in plain text to `position` in Node.
This library is for [textlint](https://github.com/textlint/textlint "textlint") and [textstat](https://github.com/azu/textstat "textstat").

@@ -15,61 +14,109 @@

The concepts `position` and `index` are the same as those explained in [Constellation/structured-source](https://github.com/Constellation/structured-source).
The concepts `position` and `index` are the same with [TxtAST Interface](https://textlint.github.io/docs/txtnode.html) and [textlint/structured-source](https://github.com/textlint/structured-source).
**Note**: the `column` property of `position` as it is **0-based** index.
- `position` is a `{ line, column }` object.
- The `column` property of `position` is **0-based**.
- The `line` property of `position` is **1-based**.
- `index` is an offset number.
- The `index` property is **0-based**.
## Usage
## API
### `Constructor(rootNode): source`
### `new StringSource(node: TxtParentNode, options?: StringSourceOptions)`
Return instance of Source.
Create new `StringSource` instance for `paragraph` Node.
## `originalIndexFromIndex(generatedIndex): number | undefined`
### `toString(): string`
Get plain text from `Paragraph` Node.
This plain text is concatenated from `value` of all children nodes of `Paragraph` Node.
```ts
import { StringSource } from "textlint-util-to-string";
const report = function (context) {
const { Syntax, report, RuleError } = context;
return {
// "This is **a** `code`."
[Syntax.Paragraph](node) {
const source = new StringSource(node);
const text = source.toString(); // => "This is a code."
}
}
};
```
In some cases, you may want to replace some characters in the plain text for avoiding false positives.
You can replace `value` of children nodes by `options.replacer`.
`options.replacer` is a function that takes a `node` and commands like `maskValue` or `emptyValue`.
If you want to modify the `value` of the node, return command function calls.
```ts
// "This is a `code`."
const source = new StringSource(paragraphNode, {
replacer({ node, maskValue }) {
if (node.type === Syntax.Code) {
return maskValue("_"); // code => ____
}
}
});
console.log(source.toString()); // => "This is a ____."
```
- `maskValue(character: string)`: mask the `value` of the node with the given `character`.
- `emptyValue()`: replace the `value` of the node with an empty string.
### `originalIndexFromIndex(generatedIndex): number | undefined`
Get original index from generated index value
## `originalPositionFromPosition(position): Position | undefined`
### `originalPositionFromPosition(position): Position | undefined`
Get original position from generated position
## `originalIndexFromPosition(generatedPosition): number | undefined`
### `originalIndexFromPosition(generatedPosition): number | undefined`
Get original index from generated position
## `originalPositionFromIndex(generatedIndex): Position | undefined`
### `originalPositionFromIndex(generatedIndex): Position | undefined`
Get original position from generated index
```js
import assert from "assert"
import {parse} from "markdown-to-ast";
import {StringSource} from "textlint-util-to-string";
## Examples
const originalText = "This is [Example!?](http://example.com/)";
const AST = parse(originalText);
const source = new StringSource(AST);
const result = source.toString();
Create plain text from `Paragraph` Node and get original position from plain text.
// StringSource#toString returns a plain text
assert.equal(result, "This is Example!?");
```js
import assert from "assert";
import { StringSource } from "textlint-util-to-string";
const report = function (context) {
const { Syntax, report, RuleError } = context;
return {
// "This is [Example!?](http://example.com/)"
[Syntax.Paragraph](node) {
const source = new StringSource(node);
const text = source.toString(); // => "This is Example!?"
// "Example" is located at the index 8 in the plain text
// ^
const index1 = result.indexOf("Example");
assert.strictEqual(index1, 8);
// The "Example" is located at the index 9 in the original text
assert.strictEqual(source.originalIndexFromIndex(index1), 9);
assert.deepStrictEqual(source.originalPositionFromPosition({
line: 1,
column: 8
}), {
line: 1,
column: 9
});
// "Example" is located at the index 8 in the plain text
// ^
let index1 = result.indexOf("Example");
assert.equal(index1, 8);
// The same "E" is located at the index 9 in the original text
assert.equal(source.originalIndexFromIndex(index1), 9);
assert.deepEqual(source.originalPositionFromPosition({
line: 1,
column: 8
}), {
line: 1,
column: 9
});
// Another example with "!", which is located at 15 in the plain text
// and at 16 in the original text
let index2 = result.indexOf("!?");
assert.equal(index2, 15);
assert.equal(source.originalIndexFromIndex(index2), 16);
// Another example with "!?", which is located at 15 in the plain text
// and at 16 in the original text
const index2 = result.indexOf("!?");
assert.strictEqual(index2, 15);
assert.strictEqual(source.originalIndexFromIndex(index2), 16);
}
}
};
```

@@ -76,0 +123,0 @@

@@ -7,2 +7,3 @@ import type { TxtNode, TxtParentNode } from "@textlint/ast-node-types";

import parse from "rehype-parse";
import { emptyValue, handleReplacerCommand, maskValue, StringSourceReplacerCommand } from "./replacer";

@@ -13,6 +14,11 @@ const isTxtNode = (node: unknown): node is TxtNode => {

const htmlProcessor = unified().use(parse, { fragment: true });
const html2hast = (html: string) => {
return unified().use(parse, { fragment: true }).parse(html);
return htmlProcessor.parse(html);
};
const isParentNode = (node: TxtNode | TxtParentNode): node is TxtParentNode => {
return "children" in node;
};
/* StringSourceIR example

@@ -40,2 +46,14 @@ Example: **Str**

};
export type StringSourceOptions = {
replacer?: ({
node,
parent
}: {
node: TxtNode | UnistNode;
parent?: TxtParentNode;
maskValue: typeof maskValue;
emptyValue: typeof emptyValue;
}) => StringSourceReplacerCommand | undefined;
};
export default class StringSource {

@@ -48,3 +66,3 @@ private rootNode: TxtParentNode;

constructor(node: TxtParentNode) {
constructor(node: TxtParentNode, options: StringSourceOptions = {}) {
this.rootNode = node;

@@ -54,3 +72,3 @@ this.tokenMaps = [];

// pre calculate
this._stringify(this.rootNode);
this._stringify({ node: this.rootNode, options });
this.originalSource = new StructuredSource(this.rootNode.raw);

@@ -233,11 +251,20 @@ this.generatedSource = new StructuredSource(this.generatedString);

private _valueOf(node: TxtNode | UnistNode, parent?: TxtParentNode): StringSourceIR | undefined {
private _valueOf({
node,
parent,
options
}: {
node: TxtNode | UnistNode;
parent?: TxtParentNode;
options: StringSourceOptions;
}): StringSourceIR | undefined {
if (!node) {
return;
}
const replaceCommand = options?.replacer?.({ node, parent, maskValue, emptyValue });
const newNode = replaceCommand ? handleReplacerCommand(replaceCommand, node) : node;
// [padding][value][padding]
// =>
// [value][value][value]
const value = this._getValue(node);
const value = this._getValue(newNode);
if (!value) {

@@ -250,6 +277,6 @@ return;

// <p><Str /></p>
if (this.isParagraphNode(parent) && this.isStringNode(node)) {
if (this.isParagraphNode(parent) && this.isStringNode(newNode)) {
return {
original: this._nodeRangeAsRelative(node),
intermediate: this._nodeRangeAsRelative(node),
original: this._nodeRangeAsRelative(newNode),
intermediate: this._nodeRangeAsRelative(newNode),
generatedValue: value

@@ -262,3 +289,3 @@ };

// => container is <strong>
const container = this.isParagraphNode(parent) ? node : parent;
const container = this.isParagraphNode(parent) ? newNode : parent;
const rawValue = container.raw as string | undefined;

@@ -288,6 +315,6 @@ if (rawValue === undefined) {

if (this.tokenMaps.length === 0) {
let textLength = addedTokenMap.intermediate[1] - addedTokenMap.intermediate[0];
const textLength = addedTokenMap.intermediate[1] - addedTokenMap.intermediate[0];
addedTokenMap["generated"] = [0, textLength];
} else {
let textLength = addedTokenMap.intermediate[1] - addedTokenMap.intermediate[0];
const textLength = addedTokenMap.intermediate[1] - addedTokenMap.intermediate[0];
addedTokenMap["generated"] = [this.generatedString.length, this.generatedString.length + textLength];

@@ -302,11 +329,20 @@ }

* does not expose plain-text fields, `toString` will
* recursively mapping
* recursively map
*
* @param {Node} node - Node to transform to a string.
* @param {Node} [parent] - Parent Node of the `node`.
* @param options
*/
private _stringify(node: TxtNode | TxtParentNode, parent?: TxtParentNode): void | StringSourceIR {
private _stringify({
node,
parent,
options
}: {
node: TxtNode | TxtParentNode;
parent?: TxtParentNode;
options: StringSourceOptions;
}): void | StringSourceIR {
const isHTML = node.type === "Html";
const currentNode = isHTML ? html2hast(node.value) : node;
const value = this._valueOf(currentNode, parent);
const value = this._valueOf({ node: currentNode, parent: parent, options });
if (value) {

@@ -322,3 +358,3 @@ return value;

}
const tokenMap = this._stringify(childNode, node);
const tokenMap = this._stringify({ node: childNode, parent: node, options });
if (tokenMap) {

@@ -330,5 +366,1 @@ this._addTokenMap(tokenMap);

}
const isParentNode = (node: TxtNode | TxtParentNode): node is TxtParentNode => {
return "children" in node;
};

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc