@plurnk/plurnk-plurnkdown 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,13 @@
1
+ # @plurnk/plurnk-plurnkdown
2
+
3
+ Plurnkdown — the [plurnk-service](https://github.com/plurnk/plurnk-service) packet house style: GFM + Mermaid + fenced Plurnk ops.
4
+
5
+ `PACKET.md` is the standard every outbound packet is built against. The linter enforces it:
6
+
7
+ - `op-fence` — a bare Plurnk op in prose belongs in a ```plurnk fence.
8
+ - `op-syntax` — fenced ops parse statement-level via `@plurnk/plurnk-grammar`.
9
+ - `run-on` — soft-warn on multi-compound run-ons; prose stays atomic (split, don't weld).
10
+
11
+ ## license
12
+
13
+ MIT © PossumTech Laboratories, LLC
@@ -0,0 +1,6 @@
1
+ import type { Diagnostic } from "./types.ts";
2
+ export default class Plurnkdown {
3
+ #private;
4
+ lint(source: string): Diagnostic[];
5
+ }
6
+ //# sourceMappingURL=Plurnkdown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Plurnkdown.d.ts","sourceRoot":"","sources":["../src/Plurnkdown.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAQ7C,MAAM,CAAC,OAAO,OAAO,UAAU;;IAC3B,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,EAAE,CAajC;CAyEJ"}
@@ -0,0 +1,100 @@
1
+ import { Lexer } from "marked";
2
+ import { PlurnkParser } from "@plurnk/plurnk-grammar";
3
+ const RUNON_LIMIT = 180; // a long run-on regardless of structure
4
+ const WELD_LIMIT = 120; // a semicolon welding clauses in a non-trivial sentence
5
+ // plurnkdown linter. Structural blocks are exempt by not being prose. Ops written bare
6
+ // in prose are flagged for fencing; ops inside a ```plurnk fence are delegated to
7
+ // plurnk-grammar for statement-level validation; prose sentences stay atomic.
8
+ export default class Plurnkdown {
9
+ lint(source) {
10
+ const diagnostics = [];
11
+ let line = 1;
12
+ for (const token of Lexer.lex(source)) {
13
+ if (token.type === "paragraph") {
14
+ this.#checkBareOps(token, line, diagnostics);
15
+ this.#checkRunOns(token, line, diagnostics);
16
+ }
17
+ else if (token.type === "code" && token.lang === "plurnk") {
18
+ this.#checkFencedOps(token.text, line, diagnostics);
19
+ }
20
+ line += this.#newlines(token.raw);
21
+ }
22
+ return diagnostics;
23
+ }
24
+ // A Plurnk op sigil (`<<`) opening a prose line is a bare op; ops must live in a
25
+ // ```plurnk fence (validated below) or an inline-code span.
26
+ #checkBareOps(token, line, diagnostics) {
27
+ token.raw.split("\n").forEach((text, index) => {
28
+ if (!/^\s*<</.test(text))
29
+ return;
30
+ diagnostics.push({
31
+ rule: "op-fence",
32
+ severity: "error",
33
+ message: "Bare Plurnk op in prose; wrap it in a ```plurnk fence.",
34
+ line: line + index,
35
+ column: 1,
36
+ });
37
+ });
38
+ }
39
+ // Soft-warn (#453): the floor model reads short atomic sentences better than dense
40
+ // compounds. Flag a long run-on (>= RUNON_LIMIT) or a semicolon-welded clause pair
41
+ // (>= WELD_LIMIT with a `;`). A `;` is not treated as a sentence split — the weld
42
+ // IS the anti-pattern. Warning, not error: it's a heuristic for human review.
43
+ #checkRunOns(token, line, diagnostics) {
44
+ const text = this.#visibleText(token.tokens ?? []);
45
+ // Per line, then per sentence — a soft line break is a unit boundary in this
46
+ // one-idea-per-line style, so a multi-line paragraph isn't read as one run-on.
47
+ for (const lineText of text.split("\n")) {
48
+ for (const raw of lineText.split(/(?<=\.)\s+/)) {
49
+ const sentence = raw.trim();
50
+ if (sentence === "")
51
+ continue;
52
+ const welded = sentence.length >= WELD_LIMIT && sentence.includes(";");
53
+ if (sentence.length < RUNON_LIMIT && !welded)
54
+ continue;
55
+ diagnostics.push({
56
+ rule: "run-on",
57
+ severity: "warning",
58
+ message: `Prose sentence is ${sentence.length} chars${welded ? " and semicolon-welded" : ""}; keep it atomic — split, don't weld.`,
59
+ line,
60
+ column: 1,
61
+ });
62
+ }
63
+ }
64
+ }
65
+ // Delegate a ```plurnk fence's ops to plurnk-grammar; surface each syntax error at
66
+ // its absolute line. Fence content line 1 sits one line below the opening fence.
67
+ #checkFencedOps(text, line, diagnostics) {
68
+ for (const item of PlurnkParser.parseStatements(text).items) {
69
+ if (item.kind !== "error")
70
+ continue;
71
+ const error = item.error;
72
+ diagnostics.push({
73
+ rule: "op-syntax",
74
+ severity: error.severity === "warning" ? "warning" : "error",
75
+ message: error.message.replace(/^Plurnk \w+ error at line \d+:\d+ - /, ""),
76
+ line: line + error.line,
77
+ column: error.column,
78
+ });
79
+ }
80
+ }
81
+ #visibleText(tokens) {
82
+ let out = "";
83
+ for (const token of tokens) {
84
+ if (token.type === "br")
85
+ continue;
86
+ const children = token.tokens;
87
+ if (children && children.length > 0) {
88
+ out += this.#visibleText(children);
89
+ continue;
90
+ }
91
+ const leaf = token;
92
+ out += leaf.text ?? leaf.raw ?? "";
93
+ }
94
+ return out;
95
+ }
96
+ #newlines(raw) {
97
+ return raw.split("\n").length - 1;
98
+ }
99
+ }
100
+ //# sourceMappingURL=Plurnkdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Plurnkdown.js","sourceRoot":"","sources":["../src/Plurnkdown.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export declare const name = "@plurnk/plurnk-plurnkdown";
2
+ export { default as Plurnkdown } from "./Plurnkdown.ts";
3
+ export type { Diagnostic, Severity } from "./types.ts";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,IAAI,8BAA8B,CAAC;AAChD,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACxD,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export const name = "@plurnk/plurnk-plurnkdown";
2
+ export { default as Plurnkdown } from "./Plurnkdown.js";
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,IAAI,GAAG,2BAA2B,CAAC;AAChD,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,9 @@
1
+ export type Severity = "error" | "warning";
2
+ export interface Diagnostic {
3
+ rule: string;
4
+ severity: Severity;
5
+ message: string;
6
+ line: number;
7
+ column: number;
8
+ }
9
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,SAAS,CAAC;AAE3C,MAAM,WAAW,UAAU;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,QAAQ,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAClB"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@plurnk/plurnk-plurnkdown",
3
+ "version": "1.0.6",
4
+ "description": "Plurnkdown — the plurnk packet house style (GFM + Mermaid + fenced Plurnk ops) and its linter.",
5
+ "keywords": [
6
+ "plurnk",
7
+ "plurnkdown",
8
+ "markdown",
9
+ "gfm",
10
+ "mermaid",
11
+ "linter"
12
+ ],
13
+ "engines": {
14
+ "node": ">=26"
15
+ },
16
+ "dependencies": {
17
+ "@plurnk/plurnk-grammar": "1.0.6",
18
+ "marked": "^18.0.5"
19
+ },
20
+ "license": "MIT",
21
+ "author": "@wikitopian",
22
+ "type": "module",
23
+ "publishConfig": {
24
+ "access": "public"
25
+ },
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "git+https://github.com/plurnk/plurnk-service.git",
29
+ "directory": "plurnk-plurnkdown"
30
+ },
31
+ "exports": {
32
+ ".": {
33
+ "plurnk-dev": "./src/index.ts",
34
+ "types": "./dist/index.d.ts",
35
+ "default": "./dist/index.js"
36
+ },
37
+ "./package.json": "./package.json"
38
+ },
39
+ "files": [
40
+ "dist/**/*",
41
+ "README.md"
42
+ ],
43
+ "scripts": {
44
+ "test:lint": "tsc --noEmit",
45
+ "test:unit": "node --conditions=plurnk-dev --test src/**/*.test.ts",
46
+ "test": "npm run test:lint && npm run test:unit",
47
+ "build:dist": "tsc -p tsconfig.build.json",
48
+ "build": "npm run build:dist",
49
+ "prepack": "npm run build"
50
+ }
51
+ }