@pyric/ui 0.1.0-alpha.17 → 0.1.0-alpha.19

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.
@@ -22,16 +22,6 @@ export interface RuleLine {
22
22
  /** A short note for skipped lines, e.g. "not checked, this is an update". */
23
23
  note?: string;
24
24
  }
25
- /**
26
- * Split the rules source into numbered lines and mark each `allow` line
27
- * with a verdict per the spec:
28
- * - the deciding rule's line → `deny`
29
- * - an allow line whose operations don't include the method → `skip`
30
- * - any other allow line → `allow`
31
- *
32
- * Verdicts are matched to source lines via `RuleEvaluation.line` (1-indexed
33
- * `allow` keyword). Lines without a matching evaluation entry get no verdict.
34
- */
35
25
  export declare function markRuleLines(rulesSource: string, evaluation: RuleEvaluation[], method: FirestoreMethod): RuleLine[];
36
26
  /** Render a trace value the way the mock shows it: JSON-ish, quoted
37
27
  * strings, `false`/`true`/`null` bare. */
@@ -1 +1 @@
1
- {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../../src/rules/components/format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAGhG;kEACkE;AAClE,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,EAAE,CASlE;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,cAAc,EAAE,GAAG,cAAc,GAAG,SAAS,CAM3F;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,UAAU,EAAE,cAAc,EAAE,EAC5B,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,MAAM,GACX,MAAM,CAuBR;AAED,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,6EAA6E;IAC7E,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAC3B,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,cAAc,EAAE,EAC5B,MAAM,EAAE,eAAe,GACtB,QAAQ,EAAE,CAsCZ;AAED;2CAC2C;AAC3C,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAYlD;AAED,mEAAmE;AACnE,wBAAgB,UAAU,CAAC,OAAO,EAAE,cAAc,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAW3E;AAED;;;;GAIG;AACH,MAAM,WAAW,QAAQ;IACvB,4CAA4C;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,sDAAsD;IACtD,GAAG,EAAE,MAAM,CAAC;IACZ,2BAA2B;IAC3B,KAAK,EAAE,OAAO,CAAC;IACf,sEAAsE;IACtE,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB"}
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../../src/rules/components/format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAGhG;kEACkE;AAClE,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,EAAE,CASlE;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,cAAc,EAAE,GAAG,cAAc,GAAG,SAAS,CAM3F;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,UAAU,EAAE,cAAc,EAAE,EAC5B,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,MAAM,GACX,MAAM,CAuBR;AAED,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,6EAA6E;IAC7E,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAkED,wBAAgB,aAAa,CAC3B,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,cAAc,EAAE,EAC5B,MAAM,EAAE,eAAe,GACtB,QAAQ,EAAE,CA2CZ;AAED;2CAC2C;AAC3C,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAYlD;AAED,mEAAmE;AACnE,wBAAgB,UAAU,CAAC,OAAO,EAAE,cAAc,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAW3E;AAED;;;;GAIG;AACH,MAAM,WAAW,QAAQ;IACvB,4CAA4C;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,sDAAsD;IACtD,GAAG,EAAE,MAAM,CAAC;IACZ,2BAA2B;IAC3B,KAAK,EAAE,OAAO,CAAC;IACf,sEAAsE;IACtE,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB"}
@@ -60,43 +60,89 @@ export function denialReason(evaluation, method, path) {
60
60
  * Verdicts are matched to source lines via `RuleEvaluation.line` (1-indexed
61
61
  * `allow` keyword). Lines without a matching evaluation entry get no verdict.
62
62
  */
63
+ function parsePyricSourceMapEntries(sourceText) {
64
+ const marker = '// @pyric-source-map:';
65
+ const markerIndex = sourceText.indexOf(marker);
66
+ const hasMarker = markerIndex !== -1;
67
+ if (!hasMarker) {
68
+ return null;
69
+ }
70
+ const jsonStart = markerIndex + marker.length;
71
+ const rawJson = sourceText.slice(jsonStart).trim();
72
+ try {
73
+ const parsed = JSON.parse(rawJson);
74
+ const isArrayPayload = Array.isArray(parsed);
75
+ if (isArrayPayload) {
76
+ return parsed;
77
+ }
78
+ return null;
79
+ }
80
+ catch {
81
+ return null;
82
+ }
83
+ }
84
+ function stripPyricSourceMap(source) {
85
+ const marker = '// @pyric-source-map:';
86
+ const markerIndex = source.indexOf(marker);
87
+ const hasMarker = markerIndex !== -1;
88
+ if (!hasMarker) {
89
+ return source;
90
+ }
91
+ return source.slice(0, markerIndex).trimEnd();
92
+ }
93
+ function mapAuthoredLineToGenerated(sourceMapEntries, authoredLine) {
94
+ const isMapMissing = sourceMapEntries === null;
95
+ if (isMapMissing) {
96
+ return authoredLine;
97
+ }
98
+ const matchingEntry = sourceMapEntries.find((entry) => entry.authoredLine === authoredLine);
99
+ const hasMatchingEntry = matchingEntry !== undefined;
100
+ if (hasMatchingEntry) {
101
+ return matchingEntry.generatedLine;
102
+ }
103
+ return authoredLine;
104
+ }
63
105
  export function markRuleLines(rulesSource, evaluation, method) {
64
106
  const deciding = decidingEvaluation(evaluation);
65
107
  const ops = methodOperations(method);
66
- // line verdict, from the evaluated rules.
108
+ const sourceMapEntries = parsePyricSourceMapEntries(rulesSource);
67
109
  const byLine = new Map();
68
- const noteByLine = new Map();
69
110
  for (const e of evaluation) {
70
- if (e.line == null)
111
+ const hasLineNumber = e.line != null;
112
+ if (!hasLineNumber)
71
113
  continue;
72
- if (e === deciding)
73
- byLine.set(e.line, 'deny');
74
- else
75
- byLine.set(e.line, 'allow');
114
+ const targetLine = mapAuthoredLineToGenerated(sourceMapEntries, e.line);
115
+ const isDecidingEvaluation = e === deciding;
116
+ if (isDecidingEvaluation) {
117
+ byLine.set(targetLine, 'deny');
118
+ }
119
+ else {
120
+ byLine.set(targetLine, 'allow');
121
+ }
76
122
  }
77
- // Detect skipped allow lines by scanning the source for `allow <ops>:`
78
- // declarations whose operations don't intersect the request method.
79
- const rawLines = rulesSource.split('\n');
123
+ const cleanSource = stripPyricSourceMap(rulesSource);
124
+ const rawLines = cleanSource.split('\n');
80
125
  const allowRe = /^\s*allow\s+([a-z,\s]+?)\s*:/;
81
126
  return rawLines.map((text, i) => {
82
127
  const number = i + 1;
83
128
  const line = { number, text };
84
129
  const fromEval = byLine.get(number);
85
- if (fromEval) {
130
+ const hasEvaluationVerdict = fromEval !== undefined;
131
+ if (hasEvaluationVerdict) {
86
132
  line.verdict = fromEval;
87
133
  return line;
88
134
  }
89
135
  const m = allowRe.exec(text);
90
- if (m) {
91
- const declared = m[1].split(',').map(s => s.trim()).filter(Boolean);
92
- const matches = declared.some(op => ops.includes(op));
93
- if (!matches) {
136
+ const isAllowLine = m !== null;
137
+ if (isAllowLine) {
138
+ const declared = m[1].split(',').map((s) => s.trim()).filter(Boolean);
139
+ const matches = declared.some((op) => ops.includes(op));
140
+ const isOperationMatched = matches;
141
+ if (!isOperationMatched) {
94
142
  line.verdict = 'skip';
95
143
  line.note = `not checked, this is a ${method}`;
96
144
  }
97
145
  else {
98
- // Declared for this method but not in the evaluation trace
99
- // (e.g. a different match block). Treat as a normal allow line.
100
146
  line.verdict = 'allow';
101
147
  }
102
148
  }
@@ -1 +1 @@
1
- {"version":3,"file":"format.js","sourceRoot":"","sources":["../../../src/rules/components/format.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"format.js","sourceRoot":"","sources":["../../../src/rules/components/format.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pyric/ui",
3
- "version": "0.1.0-alpha.17",
3
+ "version": "0.1.0-alpha.19",
4
4
  "license": "Apache-2.0",
5
5
  "homepage": "https://pyric.dev",
6
6
  "repository": {
@@ -93,7 +93,7 @@
93
93
  "react": ">=18",
94
94
  "react-dom": ">=18",
95
95
  "firebase": ">=12",
96
- "pyric": "^0.1.0-alpha.17"
96
+ "pyric": "^0.1.0-alpha.19"
97
97
  },
98
98
  "peerDependenciesMeta": {
99
99
  "@inbrowser/agent": {
@@ -109,8 +109,8 @@
109
109
  "fake-indexeddb": "^6.0.0",
110
110
  "firebase": "^12.12.0",
111
111
  "jsdom": "^29.1.1",
112
- "pyric": "^0.1.0-alpha.17",
113
- "pyric-admin": "^0.1.0-alpha.17",
112
+ "pyric": "^0.1.0-alpha.19",
113
+ "pyric-admin": "^0.1.0-alpha.19",
114
114
  "react": "^19.0.0",
115
115
  "react-dom": "^19.0.0",
116
116
  "react-test-renderer": "^19.2.6",
@@ -80,6 +80,60 @@ export interface RuleLine {
80
80
  * Verdicts are matched to source lines via `RuleEvaluation.line` (1-indexed
81
81
  * `allow` keyword). Lines without a matching evaluation entry get no verdict.
82
82
  */
83
+ function parsePyricSourceMapEntries(sourceText: string): Array<{
84
+ generatedLine: number;
85
+ authoredLine: number;
86
+ authoredCol: number;
87
+ authoredFile: string;
88
+ }> | null {
89
+ const marker = '// @pyric-source-map:';
90
+ const markerIndex = sourceText.indexOf(marker);
91
+ const hasMarker = markerIndex !== -1;
92
+ if (!hasMarker) {
93
+ return null;
94
+ }
95
+ const jsonStart = markerIndex + marker.length;
96
+ const rawJson = sourceText.slice(jsonStart).trim();
97
+ try {
98
+ const parsed = JSON.parse(rawJson);
99
+ const isArrayPayload = Array.isArray(parsed);
100
+ if (isArrayPayload) {
101
+ return parsed;
102
+ }
103
+ return null;
104
+ } catch {
105
+ return null;
106
+ }
107
+ }
108
+
109
+ function stripPyricSourceMap(source: string): string {
110
+ const marker = '// @pyric-source-map:';
111
+ const markerIndex = source.indexOf(marker);
112
+ const hasMarker = markerIndex !== -1;
113
+ if (!hasMarker) {
114
+ return source;
115
+ }
116
+ return source.slice(0, markerIndex).trimEnd();
117
+ }
118
+
119
+ function mapAuthoredLineToGenerated(
120
+ sourceMapEntries: Array<{ generatedLine: number; authoredLine: number }> | null,
121
+ authoredLine: number,
122
+ ): number {
123
+ const isMapMissing = sourceMapEntries === null;
124
+ if (isMapMissing) {
125
+ return authoredLine;
126
+ }
127
+ const matchingEntry = sourceMapEntries.find(
128
+ (entry) => entry.authoredLine === authoredLine,
129
+ );
130
+ const hasMatchingEntry = matchingEntry !== undefined;
131
+ if (hasMatchingEntry) {
132
+ return matchingEntry.generatedLine;
133
+ }
134
+ return authoredLine;
135
+ }
136
+
83
137
  export function markRuleLines(
84
138
  rulesSource: string,
85
139
  evaluation: RuleEvaluation[],
@@ -87,36 +141,41 @@ export function markRuleLines(
87
141
  ): RuleLine[] {
88
142
  const deciding = decidingEvaluation(evaluation);
89
143
  const ops = methodOperations(method);
90
- // line verdict, from the evaluated rules.
144
+ const sourceMapEntries = parsePyricSourceMapEntries(rulesSource);
91
145
  const byLine = new Map<number, LineVerdict>();
92
- const noteByLine = new Map<number, string>();
93
146
  for (const e of evaluation) {
94
- if (e.line == null) continue;
95
- if (e === deciding) byLine.set(e.line, 'deny');
96
- else byLine.set(e.line, 'allow');
147
+ const hasLineNumber = e.line != null;
148
+ if (!hasLineNumber) continue;
149
+ const targetLine = mapAuthoredLineToGenerated(sourceMapEntries, e.line!);
150
+ const isDecidingEvaluation = e === deciding;
151
+ if (isDecidingEvaluation) {
152
+ byLine.set(targetLine, 'deny');
153
+ } else {
154
+ byLine.set(targetLine, 'allow');
155
+ }
97
156
  }
98
- // Detect skipped allow lines by scanning the source for `allow <ops>:`
99
- // declarations whose operations don't intersect the request method.
100
- const rawLines = rulesSource.split('\n');
157
+ const cleanSource = stripPyricSourceMap(rulesSource);
158
+ const rawLines = cleanSource.split('\n');
101
159
  const allowRe = /^\s*allow\s+([a-z,\s]+?)\s*:/;
102
160
  return rawLines.map((text, i) => {
103
161
  const number = i + 1;
104
162
  const line: RuleLine = { number, text };
105
163
  const fromEval = byLine.get(number);
106
- if (fromEval) {
164
+ const hasEvaluationVerdict = fromEval !== undefined;
165
+ if (hasEvaluationVerdict) {
107
166
  line.verdict = fromEval;
108
167
  return line;
109
168
  }
110
169
  const m = allowRe.exec(text);
111
- if (m) {
112
- const declared = m[1].split(',').map(s => s.trim()).filter(Boolean);
113
- const matches = declared.some(op => ops.includes(op));
114
- if (!matches) {
170
+ const isAllowLine = m !== null;
171
+ if (isAllowLine) {
172
+ const declared = m[1].split(',').map((s) => s.trim()).filter(Boolean);
173
+ const matches = declared.some((op) => ops.includes(op));
174
+ const isOperationMatched = matches;
175
+ if (!isOperationMatched) {
115
176
  line.verdict = 'skip';
116
177
  line.note = `not checked, this is a ${method}`;
117
178
  } else {
118
- // Declared for this method but not in the evaluation trace
119
- // (e.g. a different match block). Treat as a normal allow line.
120
179
  line.verdict = 'allow';
121
180
  }
122
181
  }