@cuzfrog/pi-module-gates 0.17.2 → 0.18.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cuzfrog/pi-module-gates",
3
- "version": "0.17.2",
3
+ "version": "0.18.0",
4
4
  "description": "pi extension that controls the entropy of the codebase by enforcing code module boundaries.",
5
5
  "keywords": [
6
6
  "pi-package"
@@ -13,7 +13,33 @@ const goChecker: ExportChecker = {
13
13
  registerChecker(goChecker);
14
14
 
15
15
  function extractExports(src: string): Signature[] {
16
- return [...src.matchAll(
17
- /^(?:func\s+(?!\()|type\s+|var\s+|const\s+)([\p{Lu}]\w*)/gmu,
18
- )].map((m) => ({ name: m[1] }));
16
+ const out: Signature[] = [];
17
+
18
+ for (const m of src.matchAll(
19
+ /^(?:func\s+(?:\([^)]*\)\s+)?|type\s+|var\s+|const\s+)([\p{Lu}]\w*)/gmu,
20
+ )) {
21
+ out.push({ name: m[1] });
22
+ }
23
+
24
+ for (const block of src.matchAll(/(?:^|\n)(?:var|const)\s*\(([\s\S]*?)\)/g)) {
25
+ const inner = block[1];
26
+ for (const line of inner.split(/\n/)) {
27
+ const trimmed = line.trim();
28
+ if (!trimmed) continue;
29
+ const m = /^([\p{Lu}]\w*)(?:\s*(?::\s*[\w.\[\]any, |]+)?=\s*[\s\S]*|\s*$)/u.exec(trimmed);
30
+ if (m) out.push({ name: m[1] });
31
+ }
32
+ }
33
+
34
+ for (const iface of src.matchAll(/(?:^|\n)type\s+[\p{Lu}]\w*\s+interface\s*\{([\s\S]*?)\}/gu)) {
35
+ const inner = iface[1];
36
+ for (const line of inner.split(/\n/)) {
37
+ const trimmed = line.trim();
38
+ if (!trimmed) continue;
39
+ const m = /^([\p{Lu}]\w*)\s*\(/u.exec(trimmed);
40
+ if (m) out.push({ name: m[1] });
41
+ }
42
+ }
43
+
44
+ return out;
19
45
  }
@@ -14,6 +14,6 @@ registerChecker(javaChecker);
14
14
 
15
15
  function extractExports(src: string): Signature[] {
16
16
  return [...src.matchAll(
17
- /^public\s+(?:class|interface|enum|@interface|record)\s+(\w+)/gm,
18
- )].map((m) => ({ modifier: "public", name: m[1] }));
17
+ /^(?:@\w+(?:\([^)]*\))?\s+)*public\s+(?:(?:abstract|final|sealed|non-sealed|static)\s+)*(class|interface|enum|@interface|record)\s+(\w+)/gm,
18
+ )].map((m) => ({ modifier: "public", name: m[2] }));
19
19
  }
@@ -13,14 +13,26 @@ const kotlinChecker: ExportChecker = {
13
13
  registerChecker(kotlinChecker);
14
14
 
15
15
  function extractExports(src: string): Signature[] {
16
- const re = /^(?:(public|internal|protected|private)\s+)?(?:(?:data|sealed|enum|abstract|open)\s+)?(?:class|interface|object|fun|val|var|typealias)\s+(\w+)/gm;
16
+ const declRe = /^(?:@\w+(?:\([^)]*\))?\s+)*(?:(public|internal|private)\s+)?(?:(?:data|sealed|enum|abstract|open|final|inline|value|annotation|expect|actual|external)\s+)*(?:companion\s+)?(?:class|interface|object|fun|val|var|typealias)\s+(\w+)/m;
17
17
  const results: Signature[] = [];
18
- for (const m of src.matchAll(re)) {
19
- if (m[1] === "private") continue;
20
- results.push({
21
- modifier: m[1] || undefined,
22
- name: m[2],
23
- });
18
+ let depth = 0;
19
+ for (const rawLine of src.split("\n")) {
20
+ const line = rawLine.replace(/\/\/.*$/, "").replace(/\/\*.*?\*\//g, "");
21
+ if (depth === 0) {
22
+ const m = declRe.exec(line);
23
+ if (m) {
24
+ const visibility = m[1];
25
+ const name = m[2];
26
+ if (visibility === "private") {
27
+ // skip
28
+ } else {
29
+ results.push({ modifier: visibility, name });
30
+ }
31
+ }
32
+ }
33
+ depth += (line.match(/\{/g) || []).length;
34
+ depth -= (line.match(/\}/g) || []).length;
35
+ if (depth < 0) depth = 0;
24
36
  }
25
37
  return results;
26
38
  }
@@ -5,8 +5,12 @@ import type { Signature } from "../../types.ts";
5
5
  const rustChecker: ExportChecker = {
6
6
  extensions: [".rs"],
7
7
  getNewExports(before: string, after: string): Signature[] {
8
- const beforeNames = new Set(extractPubItems(before).map((s) => s.name));
9
- return extractPubItems(after).filter((sig) => !beforeNames.has(sig.name));
8
+ const beforeNames = new Set(
9
+ [...extractPubItems(before), ...extractPubUses(before)].map((s) => s.name),
10
+ );
11
+ return [...extractPubItems(after), ...extractPubUses(after)].filter(
12
+ (sig) => !beforeNames.has(sig.name),
13
+ );
10
14
  },
11
15
  };
12
16
 
@@ -14,6 +18,71 @@ registerChecker(rustChecker);
14
18
 
15
19
  function extractPubItems(src: string): Signature[] {
16
20
  return [...src.matchAll(
17
- /^(pub(?:\([^)]*\))?)\s+(?:fn|struct|enum|trait|type|const|mod)\s+(\w+)/gm,
21
+ /^(pub(?:\([^)]*\))?)(?:\s+(?:unsafe|async|const|extern(?:\s+"[^"]+")?))*\s+(?:fn|struct|enum|trait|type|const|mod|static)\s+(\w+)/gm,
18
22
  )].map((m) => ({ modifier: m[1], name: m[2] }));
19
23
  }
24
+
25
+ function extractPubUses(src: string): Signature[] {
26
+ const out: Signature[] = [];
27
+ const re = /^(pub(?:\([^)]*\))?)\s+use\s+([\s\S]*?);/gm;
28
+ for (const m of src.matchAll(re)) {
29
+ const modifier = m[1];
30
+ const body = m[2];
31
+ for (const name of extractUseNames(body)) {
32
+ out.push({ modifier, name });
33
+ }
34
+ }
35
+ return out;
36
+ }
37
+
38
+ function extractUseNames(body: string): string[] {
39
+ const trimmed = body.trim();
40
+ const groupMatch = /^(.+?)::\s*\{([\s\S]*)\}\s*$/.exec(trimmed);
41
+ if (groupMatch) {
42
+ const prefix = groupMatch[1].split("::").pop() ?? "";
43
+ return extractGroupItems(groupMatch[2], prefix);
44
+ }
45
+ const last = trimmed.split("::").pop() ?? "";
46
+ if (last === "self") {
47
+ const segments = trimmed.split("::");
48
+ segments.pop();
49
+ const fallback = segments.pop() ?? "";
50
+ return fallback ? [fallback] : [];
51
+ }
52
+ const parsed = parseRenamed(last);
53
+ return parsed && parsed !== "*" ? [parsed] : [];
54
+ }
55
+
56
+ function extractGroupItems(inner: string, prefix: string): string[] {
57
+ const out: string[] = [];
58
+ let depth = 0;
59
+ let buf = "";
60
+ for (const ch of inner) {
61
+ if (ch === "{") depth++;
62
+ else if (ch === "}") depth--;
63
+ if (ch === "," && depth === 0) {
64
+ pushItem(buf, out, prefix);
65
+ buf = "";
66
+ } else {
67
+ buf += ch;
68
+ }
69
+ }
70
+ pushItem(buf, out, prefix);
71
+ return out;
72
+ }
73
+
74
+ function pushItem(raw: string, out: string[], prefix: string): void {
75
+ const item = raw.trim();
76
+ if (!item || item === "*") return;
77
+ if (item === "self") {
78
+ if (prefix) out.push(prefix);
79
+ return;
80
+ }
81
+ out.push(parseRenamed(item));
82
+ }
83
+
84
+ function parseRenamed(item: string): string {
85
+ const asIdx = item.lastIndexOf(" as ");
86
+ const tail = asIdx >= 0 ? item.slice(asIdx + 4) : item;
87
+ return tail.split("::").pop() ?? "";
88
+ }
@@ -13,14 +13,26 @@ const scalaChecker: ExportChecker = {
13
13
  registerChecker(scalaChecker);
14
14
 
15
15
  function extractExports(src: string): Signature[] {
16
- const re = /^(?:(private(?:\[[^\]]*\])?|protected(?:\[[^\]]*\])?)\s+)?(?:class|object|trait|def|val|var|type|given|extension)\s+(\w+)/gm;
16
+ const declRe = /^(?:@\w+(?:\([^)]*\))?\s+)*(?:(private(?:\[[^\]]*\])?|protected(?:\[[^\]]*\])?|public)\s+)?(?:(?:sealed|final|abstract|lazy|opaque|implicit)\s+)*(?:case\s+)?(?:class|object|trait|def|val|var|type|enum|given|extension)\s+(\w+)/m;
17
17
  const results: Signature[] = [];
18
- for (const m of src.matchAll(re)) {
19
- if (m[1] === "private" || m[1] === "protected") continue;
20
- results.push({
21
- modifier: m[1] || undefined,
22
- name: m[2],
23
- });
18
+ let depth = 0;
19
+ for (const rawLine of src.split("\n")) {
20
+ const line = rawLine.replace(/\/\/.*$/, "");
21
+ if (depth === 0) {
22
+ const m = declRe.exec(line);
23
+ if (m) {
24
+ const visibility = m[1];
25
+ const name = m[2];
26
+ if (visibility === "private" || visibility === "protected") {
27
+ // skip bare private/protected
28
+ } else {
29
+ results.push({ modifier: visibility, name });
30
+ }
31
+ }
32
+ }
33
+ depth += (line.match(/\{/g) || []).length;
34
+ depth -= (line.match(/\}/g) || []).length;
35
+ if (depth < 0) depth = 0;
24
36
  }
25
37
  return results;
26
38
  }
@@ -12,39 +12,55 @@ const tsChecker: ExportChecker = {
12
12
 
13
13
  registerChecker(tsChecker);
14
14
 
15
+ const ANNOTATION_PREFIX = String.raw`(?:@[^\n]*\n)*[ \t]*`;
16
+ const DECL_KEYWORD = String.raw`(?:function(?:\s*\*)?|class|const|let|var|type|interface|enum)`;
17
+ const DECL_KEYWORD_NEG = String.raw`(?:function\s*\*?|class|const|let|var|type|interface|enum|abstract|async|declare)`;
18
+
15
19
  function extractExports(src: string): Signature[] {
16
- const results: Signature[] = [
17
- ...src.matchAll(
18
- /^export\s+(?:default\s+)?(?:\w+\s+)*(?:function(?:\s*\*)?|class|const|let|var|type|interface|enum)\s+(\w+)/gm,
19
- ),
20
- ].map((m) => ({ name: m[1] }));
20
+ const results: Signature[] = [];
21
+
22
+ for (const m of src.matchAll(
23
+ new RegExp(`^${ANNOTATION_PREFIX}export\\s+(?:default\\s+)?(?:\\w+\\s+)*${DECL_KEYWORD}\\s+(\\w+)`, "gm"),
24
+ )) {
25
+ results.push({ name: m[1] });
26
+ }
21
27
 
22
28
  for (const m of src.matchAll(
23
- /^export\s*(?:type\s+)?\{\s*([^}]+)\s*\}\s*from/gm,
29
+ new RegExp(`^${ANNOTATION_PREFIX}export\\s*(?:type\\s+)?\\{\\s*([^}]+?)\\s*\\}(?:\\s+from\\b)?`, "gm"),
24
30
  )) {
25
31
  const inner = m[1];
26
32
  for (const entry of inner.split(",")) {
27
- const trimmed = entry.trim();
33
+ let trimmed = entry.trim();
28
34
  if (!trimmed) continue;
29
- const asMatch = trimmed.match(/^(\w+)\s+as\s+(\w+)$/);
30
- if (asMatch) {
31
- results.push({ name: asMatch[2] });
32
- } else {
33
- results.push({ name: trimmed });
35
+ if (trimmed.startsWith("type ")) {
36
+ trimmed = trimmed.slice(5).trim();
37
+ if (!trimmed) continue;
34
38
  }
39
+ const asMatch = trimmed.match(/^(\w+)\s+as\s+(\w+)$/);
40
+ results.push({ name: asMatch ? asMatch[2] : trimmed });
35
41
  }
36
42
  }
37
43
 
38
- for (const m of src.matchAll(/^export\s*\*\s*as\s+(\w+)\s+from/gm)) {
44
+ for (const m of src.matchAll(
45
+ new RegExp(`^${ANNOTATION_PREFIX}export\\s+(?:type\\s+)?\\*\\s+from`, "gm"),
46
+ )) {
47
+ results.push({ name: "*" });
48
+ }
49
+
50
+ for (const m of src.matchAll(
51
+ new RegExp(`^${ANNOTATION_PREFIX}export\\s*\\*\\s+as\\s+(\\w+)\\s+from`, "gm"),
52
+ )) {
39
53
  results.push({ name: m[1] });
40
54
  }
41
55
 
42
- for (const m of src.matchAll(/^export\s*\*\s+from/gm)) {
43
- results.push({ name: "*" });
56
+ for (const m of src.matchAll(
57
+ new RegExp(`^${ANNOTATION_PREFIX}export\\s*=\\s*(\\w+)`, "gm"),
58
+ )) {
59
+ results.push({ name: m[1] });
44
60
  }
45
61
 
46
62
  for (const m of src.matchAll(
47
- /^export\s+default\s+(?!function|class|const|let|var|type|interface|enum|abstract|async|declare)([a-zA-Z_]\w*)/gm,
63
+ new RegExp(`^${ANNOTATION_PREFIX}export\\s+default\\s+(?!${DECL_KEYWORD_NEG})([a-zA-Z_]\\w*)`, "gm"),
48
64
  )) {
49
65
  results.push({ name: m[1] });
50
66
  }