@pretextbook/schema 0.0.1

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.
@@ -0,0 +1,9 @@
1
+ import { CompletionContext, CompletionItem } from './types';
2
+ /**
3
+ * Context-aware completions driven by salve's `walker.possible()`. Handles two
4
+ * cases: completing an element name (in content, or after `<`) and completing an
5
+ * attribute name (inside an open start tag).
6
+ */
7
+ export declare function getCompletions(context: CompletionContext): CompletionItem[];
8
+ /** Clear cached completion walker state for a document (e.g. on close). */
9
+ export declare function clearCompletionCache(uri?: string): void;
@@ -0,0 +1 @@
1
+ "use strict";const a=require("salve-annos");function e(r){return a.readTreeFromJSON(r)}exports.loadGrammarFromJSON=e;
@@ -0,0 +1,7 @@
1
+ import { readTreeFromJSON as o } from "salve-annos";
2
+ function a(r) {
3
+ return o(r);
4
+ }
5
+ export {
6
+ a as l
7
+ };
@@ -0,0 +1,8 @@
1
+ import { Grammar } from './types';
2
+ /**
3
+ * Reconstruct a salve {@link Grammar} from a precompiled JSON tree (as produced
4
+ * by `writeTreeToJSON` at schema-refresh time). This is the runtime entry point:
5
+ * it is fast (~25 ms for the PreTeXt grammar) and, unlike {@link
6
+ * "./compile"}, does not pull in salve's RNG-conversion machinery.
7
+ */
8
+ export declare function loadGrammarFromJSON(json: string): Grammar;
package/dist/index.cjs ADDED
@@ -0,0 +1,5 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const P=require("saxes"),K=require("path"),_=require("url"),G=require("salve-annos"),Z=require("./grammar-CC9aP-iu.cjs");function B(e){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(e){for(const n in e)if(n!=="default"){const r=Object.getOwnPropertyDescriptor(e,n);Object.defineProperty(t,n,r.get?r:{enumerable:!0,get:()=>e[n]})}}return t.default=e,Object.freeze(t)}const L=B(K),M={Error:1,Warning:2,Information:3,Hint:4},C={source:"pretext",defaultSeverity:M.Error,rules:[{id:"element-me-removed",match:e=>e.kind==="element-not-allowed"&&e.name==="me",message:()=>"<me> should be replaced with <md> (without any <mrow>).",severity:M.Warning},{id:"element-not-allowed",match:e=>e.kind==="element-not-allowed",message:e=>`<${e.name??"element"}> is not allowed here.`+(e.alternatives&&e.alternatives.length?` Expected one of: ${R(e.alternatives)}.`:"")},{id:"attribute-not-allowed",match:e=>e.kind==="attribute-not-allowed",message:e=>`The attribute "${e.name??""}" is not allowed on this element.`},{id:"attribute-value-invalid",match:e=>e.kind==="attribute-value-invalid"},{id:"choice-not-satisfied",match:e=>e.kind==="choice-not-satisfied",message:e=>e.alternatives&&e.alternatives.length?`Missing required content. Expected one of: ${R(e.alternatives)}.`:e.message},{id:"text-not-allowed",match:e=>e.kind==="text-not-allowed",message:()=>"Text is not allowed here."},{id:"unexpected-end",match:e=>e.kind==="unexpected-end"},{id:"xinclude-missing",match:e=>e.kind==="xinclude-missing"},{id:"xinclude-circular",match:e=>e.kind==="xinclude-circular"},{id:"well-formedness",match:e=>e.kind==="well-formedness"},{id:"duplicate-id",match:e=>e.kind==="duplicate-id"},{id:"dangling-reference",match:e=>e.kind==="dangling-reference"}]},X=[{id:"allow-document-id",match:e=>e.kind==="element-not-allowed"&&e.name==="document-id"&&e.parent==="docinfo",suppress:!0},{id:"allow-blurb",match:e=>e.kind==="element-not-allowed"&&e.name==="blurb"&&e.parent==="docinfo",suppress:!0}],J={...C,rules:[...X,...C.rules]};function R(e){const t=[...new Set(e)],n=t.slice(0,12).map(r=>`<${r}>`);return t.length>n.length&&n.push(`… (${t.length-n.length} more)`),n.join(", ")}function F(e,t=C){const n=t.defaultSeverity??M.Error,r=t.source??"pretext",s=[];for(const a of e){const l=t.rules.find(o=>o.match(a));l?.suppress||s.push({range:a.range,severity:l?.severity??n,code:l?.id,source:r,message:l?.message?l.message(a):a.message})}return s}const Q=/<xi:include\b[^>]*?\bhref\s*=\s*("|')(.*?)\1[^>]*?\/>/;function T(){const e=require("fs");return t=>{try{return e.readFileSync(t,"utf8")}catch{return}}}function Y(e){const t=e.match(/^?\s*<\?xml\b.*?\?>/s);if(!t)return{text:e,removedLines:0};const n=t[0],r=(n.match(/\n/g)??[]).length;return{text:e.slice(n.length),removedLines:r}}function ee(e){return e.startsWith("file:")?_.fileURLToPath(e):e}function te(e){return _.pathToFileURL(e).toString()}function W(e,t,n=T()){const r=[];function s(o,h,b){const d=o.split(`
2
+ `),m=[],p=[];for(let w=0;w<d.length;w++){const v=d[w],y=Q.exec(v);if(!y){m.push(v),p.push({uri:h,line:w,columnShift:0});continue}const S=v.slice(0,y.index),N=v.slice(y.index+y[0].length),i=y[2],c=L.dirname(ee(h)),u=L.resolve(c,i),f=te(u);if(S.length>0&&(m.push(S),p.push({uri:h,line:w,columnShift:0})),b.includes(f))r.push({kind:"xinclude-circular",message:`Circular xi:include detected for "${i}".`,uri:h,line:w,column:y.index,length:y[0].length});else{const x=n(u);if(x===void 0)r.push({kind:"xinclude-missing",message:`Cannot resolve xi:include target "${i}".`,uri:h,line:w,column:y.index,length:y[0].length});else{const A=Y(x),g=s(A.text,f,[...b,f]);for(let E=0;E<g.lines.length;E++)m.push(g.lines[E]),p.push(g.origin[E])}}N.trim().length>0&&(m.push(N),p.push({uri:h,line:w,columnShift:0}))}return{lines:m,origin:p}}const{lines:a,origin:l}=s(e,t,[t]);return{text:a.join(`
3
+ `),origin:l,problems:r}}const ne="http://www.w3.org/2000/xmlns/",re="http://www.w3.org/XML/1998/namespace",se={xref:["ref","first","last"],fragref:["ref"]};function ae(e,t,n={}){const r=n.uri??"untitled:document",s=n.ruleset??C,a=n.resolveXIncludes??!0,l=n.readFile??T();q(n.signal);let o=e,h;const b=[];if(a&&/<xi:include\b/.test(e)){const d=W(e,r,l);o=d.text,h=d.origin;for(const m of d.problems)b.push({kind:m.kind,message:m.message,uri:m.uri,range:ce(m.line,m.column,m.length)})}return b.push(...ie(o,t,r,h,n.signal)),oe(b,r,s)}function ie(e,t,n,r,s){const a=t.newWalker(),l=[],o=new P.SaxesParser({xmlns:!0,position:!0}),h=new Set,b=[];let d=0;const m=[];let p=null;const w=(i,c)=>{if(!r)return{uri:n,line:i,char:c};const u=r[i]??r[r.length-1];return u?{uri:u.uri,line:u.line,char:Math.max(0,c-u.columnShift)}:{uri:n,line:i,char:c}},v=(i,c,u)=>{const f=w(i,c),x=w(i,u);return{uri:f.uri,range:{start:{line:f.line,character:Math.max(0,f.char)},end:{line:x.line,character:Math.max(f.char,x.char)}}}},y=(i,c)=>{const u=m.length?[...m]:void 0,f=m.length?m[m.length-1]:void 0;for(const x of i){const A=le(x);l.push({...A,parent:f,ancestors:u,uri:c.uri,range:c.range})}},S=(i,c,u)=>{const f=a.fireEvent(i,c);Array.isArray(f)&&y(f,u)};o.on("opentagstart",i=>{const c=o.line-1,u=o.column-1,f=u-i.name.length,x=Math.max(0,f-1);p={line:c,char:x,length:u-x}}),o.on("opentag",i=>{d++;const c=p??{line:o.line-1,char:Math.max(0,o.column-1),length:1},u=v(c.line,c.char,c.char+c.length);S("enterStartTag",[i.uri??"",i.local??i.name],u);const f=i.local??i.name;m.push(f);const x=se[f];for(const A of Object.keys(i.attributes)){const g=i.attributes[A];if(g.prefix==="xmlns"||g.name==="xmlns"||g.uri===ne)continue;const E=g.local??g.name;g.uri===re&&E==="id"?h.has(g.value)?l.push({kind:"duplicate-id",message:`The xml:id "${g.value}" is already used elsewhere in this document.`,name:g.value,parent:f,ancestors:[...m],uri:u.uri,range:u.range}):h.add(g.value):x?.includes(E)&&b.push({value:g.value,loc:u,parent:f,ancestors:[...m]}),S("attributeName",[g.uri??"",g.local??g.name],u),S("attributeValue",[g.value],u)}S("leaveStartTag",[],u)}),o.on("closetag",i=>{const c=o.line-1,u=Math.max(0,o.column-1),f=v(c,Math.max(0,u-1),u);S("endTag",[i.uri??"",i.local??i.name],f),m.pop(),d=Math.max(0,d-1)}),o.on("text",i=>{if(d===0||i.length===0)return;const c=o.line-1,u=Math.max(0,o.column-1),f=Math.max(0,u-ue(i)),x=v(c,f,u);S("text",[i],x)}),o.on("error",i=>{const c=o.line-1,u=Math.max(0,o.column-1),f=w(c,u);l.push({kind:"well-formedness",message:i.message,parent:m.length?m[m.length-1]:void 0,ancestors:m.length?[...m]:void 0,uri:f.uri,range:{start:{line:f.line,character:f.char},end:{line:f.line,character:f.char+1}}})});try{for(let c=0;c<e.length;c+=65536)q(s),o.write(e.slice(c,c+65536));o.close()}catch(i){if(de(i))throw i}const N=a.end();if(Array.isArray(N)&&N.length){const i=Math.max(0,me(e)-1),c=v(i,0,1);y(N,c)}for(const i of b)h.has(i.value)||l.push({kind:"dangling-reference",message:`No element with xml:id "${i.value}" exists in this document.`,name:i.value,parent:i.parent,ancestors:i.ancestors,uri:i.loc.uri,range:i.loc.range});return l}function oe(e,t,n){const r=new Map;for(const a of e){const l=r.get(a.uri)??[];l.push(a),r.set(a.uri,l)}const s={};for(const[a,l]of r)s[a]=F(l,n);return s[t]||(s[t]=[]),{diagnostics:s[t],diagnosticsByUri:s}}function le(e){const t=e,n=t.constructor?.name??"",r=t.msg??t.toString();let s="other";switch(n){case"ElementNameError":s="element-not-allowed";break;case"AttributeNameError":s="attribute-not-allowed";break;case"AttributeValueError":s="attribute-value-invalid";break;case"ChoiceError":s="choice-not-satisfied";break;default:/text (is )?not allowed/i.test(r)?s="text-not-allowed":/must choose|tag required|incomplete|nothing else may follow/i.test(r)&&(s="choice-not-satisfied")}const a=O(t.name),l=s==="choice-not-satisfied"&&typeof t.getNames=="function"?[...new Set(t.getNames().flatMap(o=>O(o)))]:void 0;return{kind:s,message:r,name:a[0],alternatives:l&&l.length?l:void 0}}function O(e){if(!e||typeof e!="object")return[];const t=e;if(typeof t.toArray=="function"){const r=t.toArray();if(r)return r.map(s=>s.name??s.toObject?.().name).filter(s=>typeof s=="string")}const n=t.toObject?.();return n&&typeof n.name=="string"?[n.name]:typeof t.name=="string"?[t.name]:[]}function ce(e,t,n){return{start:{line:e,character:t},end:{line:e,character:t+n}}}function ue(e){const t=e.lastIndexOf(`
4
+ `);return t===-1?e.length:e.length-t-1}function me(e){let t=1;for(let n=0;n<e.length;n++)e.charCodeAt(n)===10&&t++;return t}function q(e){if(e?.aborted)throw fe()}function fe(){const e=new Error("Validation aborted");return e.name="AbortError",e}function de(e){return e instanceof Error&&e.name==="AbortError"}const D={Class:7,Property:10},he="http://www.w3.org/2000/xmlns/",j={"http://www.w3.org/XML/1998/namespace":"xml","http://www.w3.org/2001/XInclude":"xi"};function z(e,t){return e&&j[e]?`${j[e]}:${t}`:t}function ge(e){const{text:t,position:n,grammar:r,uri:s}=e,a=Se(t,n),l=t.slice(0,a),o=l.lastIndexOf("<"),h=l.lastIndexOf(">");if(!(o>h))return $(r,l,"",s);const d=l.slice(o);if(d.startsWith("</")||d.startsWith("<!")||d.startsWith("<?"))return[];const p=d.match(/^<([A-Za-z_][\w.:-]*)?/)?.[1]??"",w=d.slice(1+p.length);if(!/\s/.test(w))return $(r,l.slice(0,o),p,s);const v=ve(d);return v===null?[]:pe(r,l.slice(0,o),p,d,v,s)}function $(e,t,n,r){const s=U(e,t,r);if(!s)return[];const a=V(s.possible(),"enterStartTag");return H(a,n,D.Class)}function pe(e,t,n,r,s,a){const l=U(e,t,a);if(!l)return[];const o=l.clone(),h=o.fireEvent("enterStartTag",["",n]);if(Array.isArray(h))return[];const b=new Set(ye(r).map(p=>p.name)),d=o.possibleAttributes?o.possibleAttributes():o.possible(),m=V(d,"attributeName").filter(p=>!b.has(z(p.ns,p.name)));return H(m,s,D.Property)}class we{grammar;walker;parser;prefix="";depth=0;failed=!1;constructor(t){this.grammar=t,this.walker=t.newWalker(new G.DefaultNameResolver),this.parser=new P.SaxesParser({xmlns:!0,position:!0});const n=(r,s)=>{this.failed||this.walker.fireEvent(r,s)};this.parser.on("opentag",r=>{this.depth++,n("enterStartTag",[r.uri??"",r.local??r.name]);for(const s of Object.keys(r.attributes)){const a=r.attributes[s];a.prefix==="xmlns"||a.name==="xmlns"||a.uri===he||(n("attributeName",[a.uri??"",a.local??a.name]),n("attributeValue",[a.value]))}n("leaveStartTag",[])}),this.parser.on("closetag",r=>{n("endTag",[r.uri??"",r.local??r.name]),this.depth=Math.max(0,this.depth-1)}),this.parser.on("text",r=>{this.depth>0&&r.length>0&&n("text",[r])}),this.parser.on("error",()=>{this.failed=!0})}feed(t){try{this.parser.write(t)}catch{}this.prefix+=t}}const xe=20,k=new Map;function I(e,t){if(k.delete(e),k.set(e,t),k.size>xe){const n=k.keys().next().value;n!==void 0&&k.delete(n)}}function U(e,t,n){if(n){const s=k.get(n);if(s&&s.grammar===e&&t.startsWith(s.prefix)){const a=t.slice(s.prefix.length);return a.length>0&&s.feed(a),I(n,s),s.walker}}const r=new we(e);return r.feed(t),n&&I(n,r),r.walker}function be(e){e?k.delete(e):k.clear()}function V(e,t){const n=new Set,r=[];for(const s of e){if(s.name!==t||!s.namePattern)continue;const a=s.namePattern.toArray?.(),l=a||(s.namePattern.toObject?[s.namePattern.toObject()]:[]);for(const o of l){if(!o||typeof o.name!="string")continue;const h=`${o.ns??""}:${o.name}`;n.has(h)||(n.add(h),r.push(o))}}return r}function H(e,t,n){const r=t.toLowerCase();return e.map(s=>({display:z(s.ns,s.name),doc:s.documentation})).filter(s=>s.display.toLowerCase().startsWith(r)).sort((s,a)=>s.display.localeCompare(a.display)).map(s=>{const a={label:s.display,kind:n};return s.doc&&(a.documentation=s.doc),a})}function ve(e){const t=e.replace(/^<[\w.:-]*/,"");let n=!1,r="";for(let a=0;a<t.length;a++){const l=t[a];n?l===r&&(n=!1):(l==='"'||l==="'")&&(n=!0,r=l)}return n?null:e.match(/([A-Za-z_][\w.:-]*)?$/)?.[1]??""}function ye(e){const t=[],n=/([A-Za-z_][\w.:-]*)\s*=\s*("([^"]*)"|'([^']*)')/g;let r;for(;(r=n.exec(e))!==null;)t.push({name:r[1],value:r[3]??r[4]??""});return t}function Se(e,t){let n=0,r=0;for(;n<t.line;){const s=e.indexOf(`
5
+ `,r);if(s===-1)return e.length;r=s+1,n++}return Math.min(e.length,r+t.character)}exports.loadGrammarFromJSON=Z.loadGrammarFromJSON;exports.Severity=M;exports.applyRules=F;exports.clearCompletionCache=be;exports.defaultFileReader=T;exports.defaultRuleset=C;exports.getCompletions=ge;exports.relaxedRules=X;exports.relaxedRuleset=J;exports.resolveXIncludes=W;exports.validateDocument=ae;
@@ -0,0 +1,6 @@
1
+ export { validateDocument } from './validate';
2
+ export { getCompletions, clearCompletionCache } from './completions';
3
+ export { loadGrammarFromJSON } from './grammar';
4
+ export { applyRules, defaultRuleset, relaxedRuleset, relaxedRules, Severity, } from './rules';
5
+ export { resolveXIncludes, defaultFileReader, type OriginEntry, type IncludeProblem, type ResolvedDocument, } from './xinclude';
6
+ export type { Grammar, Diagnostic, CompletionItem, CompletionContext, Range, Position, SchemaError, SchemaErrorKind, Rule, Ruleset, DiagnosticSeverityValue, FileReader, ValidateOptions, ValidationResult, } from './types';
package/dist/index.js ADDED
@@ -0,0 +1,577 @@
1
+ import { SaxesParser as W } from "saxes";
2
+ import * as L from "path";
3
+ import { fileURLToPath as U, pathToFileURL as V } from "url";
4
+ import { DefaultNameResolver as z } from "salve-annos";
5
+ import { l as Ne } from "./grammar-CU0Faawl.js";
6
+ const C = {
7
+ Error: 1,
8
+ Warning: 2,
9
+ Information: 3,
10
+ Hint: 4
11
+ }, M = {
12
+ source: "pretext",
13
+ defaultSeverity: C.Error,
14
+ rules: [
15
+ {
16
+ id: "element-me-removed",
17
+ match: (e) => e.kind === "element-not-allowed" && e.name === "me",
18
+ message: () => "<me> should be replaced with <md> (without any <mrow>).",
19
+ severity: C.Warning
20
+ },
21
+ {
22
+ id: "element-not-allowed",
23
+ match: (e) => e.kind === "element-not-allowed",
24
+ message: (e) => `<${e.name ?? "element"}> is not allowed here.` + (e.alternatives && e.alternatives.length ? ` Expected one of: ${T(e.alternatives)}.` : "")
25
+ },
26
+ {
27
+ id: "attribute-not-allowed",
28
+ match: (e) => e.kind === "attribute-not-allowed",
29
+ message: (e) => `The attribute "${e.name ?? ""}" is not allowed on this element.`
30
+ },
31
+ {
32
+ id: "attribute-value-invalid",
33
+ match: (e) => e.kind === "attribute-value-invalid"
34
+ },
35
+ {
36
+ id: "choice-not-satisfied",
37
+ match: (e) => e.kind === "choice-not-satisfied",
38
+ message: (e) => e.alternatives && e.alternatives.length ? `Missing required content. Expected one of: ${T(
39
+ e.alternatives
40
+ )}.` : e.message
41
+ },
42
+ {
43
+ id: "text-not-allowed",
44
+ match: (e) => e.kind === "text-not-allowed",
45
+ message: () => "Text is not allowed here."
46
+ },
47
+ {
48
+ id: "unexpected-end",
49
+ match: (e) => e.kind === "unexpected-end"
50
+ },
51
+ {
52
+ id: "xinclude-missing",
53
+ match: (e) => e.kind === "xinclude-missing"
54
+ },
55
+ {
56
+ id: "xinclude-circular",
57
+ match: (e) => e.kind === "xinclude-circular"
58
+ },
59
+ {
60
+ id: "well-formedness",
61
+ match: (e) => e.kind === "well-formedness"
62
+ },
63
+ {
64
+ id: "duplicate-id",
65
+ match: (e) => e.kind === "duplicate-id"
66
+ },
67
+ {
68
+ id: "dangling-reference",
69
+ match: (e) => e.kind === "dangling-reference"
70
+ }
71
+ ]
72
+ }, H = [
73
+ {
74
+ // <document-id> is used by some publishers / build pipelines inside
75
+ // <docinfo> but isn't in the stable schema yet.
76
+ id: "allow-document-id",
77
+ match: (e) => e.kind === "element-not-allowed" && e.name === "document-id" && e.parent === "docinfo",
78
+ suppress: !0
79
+ },
80
+ {
81
+ // <blurb> inside <docinfo> (short description used by some output formats).
82
+ id: "allow-blurb",
83
+ match: (e) => e.kind === "element-not-allowed" && e.name === "blurb" && e.parent === "docinfo",
84
+ suppress: !0
85
+ }
86
+ ], ve = {
87
+ ...M,
88
+ rules: [...H, ...M.rules]
89
+ };
90
+ function T(e) {
91
+ const t = [...new Set(e)], r = t.slice(0, 12).map((n) => `<${n}>`);
92
+ return t.length > r.length && r.push(`… (${t.length - r.length} more)`), r.join(", ");
93
+ }
94
+ function K(e, t = M) {
95
+ const r = t.defaultSeverity ?? C.Error, n = t.source ?? "pretext", s = [];
96
+ for (const a of e) {
97
+ const l = t.rules.find((o) => o.match(a));
98
+ l?.suppress || s.push({
99
+ range: a.range,
100
+ severity: l?.severity ?? r,
101
+ code: l?.id,
102
+ source: n,
103
+ message: l?.message ? l.message(a) : a.message
104
+ });
105
+ }
106
+ return s;
107
+ }
108
+ const Z = /<xi:include\b[^>]*?\bhref\s*=\s*("|')(.*?)\1[^>]*?\/>/;
109
+ function X() {
110
+ const e = require("fs");
111
+ return (t) => {
112
+ try {
113
+ return e.readFileSync(t, "utf8");
114
+ } catch {
115
+ return;
116
+ }
117
+ };
118
+ }
119
+ function B(e) {
120
+ const t = e.match(/^?\s*<\?xml\b.*?\?>/s);
121
+ if (!t)
122
+ return { text: e, removedLines: 0 };
123
+ const r = t[0], n = (r.match(/\n/g) ?? []).length;
124
+ return { text: e.slice(r.length), removedLines: n };
125
+ }
126
+ function G(e) {
127
+ return e.startsWith("file:") ? U(e) : e;
128
+ }
129
+ function J(e) {
130
+ return V(e).toString();
131
+ }
132
+ function Q(e, t, r = X()) {
133
+ const n = [];
134
+ function s(o, d, b) {
135
+ const h = o.split(`
136
+ `), m = [], p = [];
137
+ for (let w = 0; w < h.length; w++) {
138
+ const v = h[w], y = Z.exec(v);
139
+ if (!y) {
140
+ m.push(v), p.push({ uri: d, line: w, columnShift: 0 });
141
+ continue;
142
+ }
143
+ const k = v.slice(0, y.index), A = v.slice(y.index + y[0].length), i = y[2], c = L.dirname(G(d)), u = L.resolve(c, i), f = J(u);
144
+ if (k.length > 0 && (m.push(k), p.push({ uri: d, line: w, columnShift: 0 })), b.includes(f))
145
+ n.push({
146
+ kind: "xinclude-circular",
147
+ message: `Circular xi:include detected for "${i}".`,
148
+ uri: d,
149
+ line: w,
150
+ column: y.index,
151
+ length: y[0].length
152
+ });
153
+ else {
154
+ const x = r(u);
155
+ if (x === void 0)
156
+ n.push({
157
+ kind: "xinclude-missing",
158
+ message: `Cannot resolve xi:include target "${i}".`,
159
+ uri: d,
160
+ line: w,
161
+ column: y.index,
162
+ length: y[0].length
163
+ });
164
+ else {
165
+ const N = B(x), g = s(N.text, f, [...b, f]);
166
+ for (let E = 0; E < g.lines.length; E++)
167
+ m.push(g.lines[E]), p.push(g.origin[E]);
168
+ }
169
+ }
170
+ A.trim().length > 0 && (m.push(A), p.push({ uri: d, line: w, columnShift: 0 }));
171
+ }
172
+ return { lines: m, origin: p };
173
+ }
174
+ const { lines: a, origin: l } = s(e, t, [t]);
175
+ return { text: a.join(`
176
+ `), origin: l, problems: n };
177
+ }
178
+ const Y = "http://www.w3.org/2000/xmlns/", ee = "http://www.w3.org/XML/1998/namespace", te = {
179
+ xref: ["ref", "first", "last"],
180
+ fragref: ["ref"]
181
+ };
182
+ function ye(e, t, r = {}) {
183
+ const n = r.uri ?? "untitled:document", s = r.ruleset ?? M, a = r.resolveXIncludes ?? !0, l = r.readFile ?? X();
184
+ j(r.signal);
185
+ let o = e, d;
186
+ const b = [];
187
+ if (a && /<xi:include\b/.test(e)) {
188
+ const h = Q(e, n, l);
189
+ o = h.text, d = h.origin;
190
+ for (const m of h.problems)
191
+ b.push({
192
+ kind: m.kind,
193
+ message: m.message,
194
+ uri: m.uri,
195
+ range: ae(m.line, m.column, m.length)
196
+ });
197
+ }
198
+ return b.push(...ne(o, t, n, d, r.signal)), re(b, n, s);
199
+ }
200
+ function ne(e, t, r, n, s) {
201
+ const a = t.newWalker(), l = [], o = new W({
202
+ xmlns: !0,
203
+ position: !0
204
+ }), d = /* @__PURE__ */ new Set(), b = [];
205
+ let h = 0;
206
+ const m = [];
207
+ let p = null;
208
+ const w = (i, c) => {
209
+ if (!n)
210
+ return { uri: r, line: i, char: c };
211
+ const u = n[i] ?? n[n.length - 1];
212
+ return u ? {
213
+ uri: u.uri,
214
+ line: u.line,
215
+ char: Math.max(0, c - u.columnShift)
216
+ } : { uri: r, line: i, char: c };
217
+ }, v = (i, c, u) => {
218
+ const f = w(i, c), x = w(i, u);
219
+ return {
220
+ uri: f.uri,
221
+ range: {
222
+ start: { line: f.line, character: Math.max(0, f.char) },
223
+ end: { line: x.line, character: Math.max(f.char, x.char) }
224
+ }
225
+ };
226
+ }, y = (i, c) => {
227
+ const u = m.length ? [...m] : void 0, f = m.length ? m[m.length - 1] : void 0;
228
+ for (const x of i) {
229
+ const N = se(x);
230
+ l.push({
231
+ ...N,
232
+ parent: f,
233
+ ancestors: u,
234
+ uri: c.uri,
235
+ range: c.range
236
+ });
237
+ }
238
+ }, k = (i, c, u) => {
239
+ const f = a.fireEvent(i, c);
240
+ Array.isArray(f) && y(f, u);
241
+ };
242
+ o.on("opentagstart", (i) => {
243
+ const c = o.line - 1, u = o.column - 1, f = u - i.name.length, x = Math.max(0, f - 1);
244
+ p = { line: c, char: x, length: u - x };
245
+ }), o.on("opentag", (i) => {
246
+ h++;
247
+ const c = p ?? {
248
+ line: o.line - 1,
249
+ char: Math.max(0, o.column - 1),
250
+ length: 1
251
+ }, u = v(c.line, c.char, c.char + c.length);
252
+ k("enterStartTag", [i.uri ?? "", i.local ?? i.name], u);
253
+ const f = i.local ?? i.name;
254
+ m.push(f);
255
+ const x = te[f];
256
+ for (const N of Object.keys(i.attributes)) {
257
+ const g = i.attributes[N];
258
+ if (g.prefix === "xmlns" || g.name === "xmlns" || g.uri === Y)
259
+ continue;
260
+ const E = g.local ?? g.name;
261
+ g.uri === ee && E === "id" ? d.has(g.value) ? l.push({
262
+ kind: "duplicate-id",
263
+ message: `The xml:id "${g.value}" is already used elsewhere in this document.`,
264
+ name: g.value,
265
+ parent: f,
266
+ ancestors: [...m],
267
+ uri: u.uri,
268
+ range: u.range
269
+ }) : d.add(g.value) : x?.includes(E) && b.push({
270
+ value: g.value,
271
+ loc: u,
272
+ parent: f,
273
+ ancestors: [...m]
274
+ }), k("attributeName", [g.uri ?? "", g.local ?? g.name], u), k("attributeValue", [g.value], u);
275
+ }
276
+ k("leaveStartTag", [], u);
277
+ }), o.on("closetag", (i) => {
278
+ const c = o.line - 1, u = Math.max(0, o.column - 1), f = v(c, Math.max(0, u - 1), u);
279
+ k("endTag", [i.uri ?? "", i.local ?? i.name], f), m.pop(), h = Math.max(0, h - 1);
280
+ }), o.on("text", (i) => {
281
+ if (h === 0 || i.length === 0)
282
+ return;
283
+ const c = o.line - 1, u = Math.max(0, o.column - 1), f = Math.max(0, u - ie(i)), x = v(c, f, u);
284
+ k("text", [i], x);
285
+ }), o.on("error", (i) => {
286
+ const c = o.line - 1, u = Math.max(0, o.column - 1), f = w(c, u);
287
+ l.push({
288
+ kind: "well-formedness",
289
+ message: i.message,
290
+ parent: m.length ? m[m.length - 1] : void 0,
291
+ ancestors: m.length ? [...m] : void 0,
292
+ uri: f.uri,
293
+ range: {
294
+ start: { line: f.line, character: f.char },
295
+ end: { line: f.line, character: f.char + 1 }
296
+ }
297
+ });
298
+ });
299
+ try {
300
+ for (let c = 0; c < e.length; c += 65536)
301
+ j(s), o.write(e.slice(c, c + 65536));
302
+ o.close();
303
+ } catch (i) {
304
+ if (ce(i))
305
+ throw i;
306
+ }
307
+ const A = a.end();
308
+ if (Array.isArray(A) && A.length) {
309
+ const i = Math.max(0, oe(e) - 1), c = v(i, 0, 1);
310
+ y(A, c);
311
+ }
312
+ for (const i of b)
313
+ d.has(i.value) || l.push({
314
+ kind: "dangling-reference",
315
+ message: `No element with xml:id "${i.value}" exists in this document.`,
316
+ name: i.value,
317
+ parent: i.parent,
318
+ ancestors: i.ancestors,
319
+ uri: i.loc.uri,
320
+ range: i.loc.range
321
+ });
322
+ return l;
323
+ }
324
+ function re(e, t, r) {
325
+ const n = /* @__PURE__ */ new Map();
326
+ for (const a of e) {
327
+ const l = n.get(a.uri) ?? [];
328
+ l.push(a), n.set(a.uri, l);
329
+ }
330
+ const s = {};
331
+ for (const [a, l] of n)
332
+ s[a] = K(l, r);
333
+ return s[t] || (s[t] = []), { diagnostics: s[t], diagnosticsByUri: s };
334
+ }
335
+ function se(e) {
336
+ const t = e, r = t.constructor?.name ?? "", n = t.msg ?? t.toString();
337
+ let s = "other";
338
+ switch (r) {
339
+ case "ElementNameError":
340
+ s = "element-not-allowed";
341
+ break;
342
+ case "AttributeNameError":
343
+ s = "attribute-not-allowed";
344
+ break;
345
+ case "AttributeValueError":
346
+ s = "attribute-value-invalid";
347
+ break;
348
+ case "ChoiceError":
349
+ s = "choice-not-satisfied";
350
+ break;
351
+ default:
352
+ /text (is )?not allowed/i.test(n) ? s = "text-not-allowed" : /must choose|tag required|incomplete|nothing else may follow/i.test(n) && (s = "choice-not-satisfied");
353
+ }
354
+ const a = R(t.name), l = s === "choice-not-satisfied" && typeof t.getNames == "function" ? [...new Set(t.getNames().flatMap((o) => R(o)))] : void 0;
355
+ return {
356
+ kind: s,
357
+ message: n,
358
+ name: a[0],
359
+ alternatives: l && l.length ? l : void 0
360
+ };
361
+ }
362
+ function R(e) {
363
+ if (!e || typeof e != "object")
364
+ return [];
365
+ const t = e;
366
+ if (typeof t.toArray == "function") {
367
+ const n = t.toArray();
368
+ if (n)
369
+ return n.map((s) => s.name ?? s.toObject?.().name).filter((s) => typeof s == "string");
370
+ }
371
+ const r = t.toObject?.();
372
+ return r && typeof r.name == "string" ? [r.name] : typeof t.name == "string" ? [t.name] : [];
373
+ }
374
+ function ae(e, t, r) {
375
+ return {
376
+ start: { line: e, character: t },
377
+ end: { line: e, character: t + r }
378
+ };
379
+ }
380
+ function ie(e) {
381
+ const t = e.lastIndexOf(`
382
+ `);
383
+ return t === -1 ? e.length : e.length - t - 1;
384
+ }
385
+ function oe(e) {
386
+ let t = 1;
387
+ for (let r = 0; r < e.length; r++)
388
+ e.charCodeAt(r) === 10 && t++;
389
+ return t;
390
+ }
391
+ function j(e) {
392
+ if (e?.aborted)
393
+ throw le();
394
+ }
395
+ function le() {
396
+ const e = new Error("Validation aborted");
397
+ return e.name = "AbortError", e;
398
+ }
399
+ function ce(e) {
400
+ return e instanceof Error && e.name === "AbortError";
401
+ }
402
+ const P = {
403
+ Class: 7,
404
+ Property: 10
405
+ }, ue = "http://www.w3.org/2000/xmlns/", $ = {
406
+ "http://www.w3.org/XML/1998/namespace": "xml",
407
+ "http://www.w3.org/2001/XInclude": "xi"
408
+ };
409
+ function _(e, t) {
410
+ return e && $[e] ? `${$[e]}:${t}` : t;
411
+ }
412
+ function ke(e) {
413
+ const { text: t, position: r, grammar: n, uri: s } = e, a = pe(t, r), l = t.slice(0, a), o = l.lastIndexOf("<"), d = l.lastIndexOf(">");
414
+ if (!(o > d))
415
+ return I(n, l, "", s);
416
+ const h = l.slice(o);
417
+ if (h.startsWith("</") || h.startsWith("<!") || h.startsWith("<?"))
418
+ return [];
419
+ const p = h.match(/^<([A-Za-z_][\w.:-]*)?/)?.[1] ?? "", w = h.slice(1 + p.length);
420
+ if (!/\s/.test(w))
421
+ return I(n, l.slice(0, o), p, s);
422
+ const v = de(h);
423
+ return v === null ? [] : me(
424
+ n,
425
+ l.slice(0, o),
426
+ p,
427
+ h,
428
+ v,
429
+ s
430
+ );
431
+ }
432
+ function I(e, t, r, n) {
433
+ const s = F(e, t, n);
434
+ if (!s)
435
+ return [];
436
+ const a = q(s.possible(), "enterStartTag");
437
+ return D(a, r, P.Class);
438
+ }
439
+ function me(e, t, r, n, s, a) {
440
+ const l = F(e, t, a);
441
+ if (!l)
442
+ return [];
443
+ const o = l.clone(), d = o.fireEvent("enterStartTag", ["", r]);
444
+ if (Array.isArray(d))
445
+ return [];
446
+ const b = new Set(
447
+ ge(n).map((p) => p.name)
448
+ ), h = o.possibleAttributes ? o.possibleAttributes() : o.possible(), m = q(h, "attributeName").filter(
449
+ (p) => !b.has(_(p.ns, p.name))
450
+ );
451
+ return D(m, s, P.Property);
452
+ }
453
+ class fe {
454
+ grammar;
455
+ walker;
456
+ parser;
457
+ prefix = "";
458
+ depth = 0;
459
+ failed = !1;
460
+ constructor(t) {
461
+ this.grammar = t, this.walker = t.newWalker(new z()), this.parser = new W({
462
+ xmlns: !0,
463
+ position: !0
464
+ });
465
+ const r = (n, s) => {
466
+ this.failed || this.walker.fireEvent(n, s);
467
+ };
468
+ this.parser.on("opentag", (n) => {
469
+ this.depth++, r("enterStartTag", [n.uri ?? "", n.local ?? n.name]);
470
+ for (const s of Object.keys(n.attributes)) {
471
+ const a = n.attributes[s];
472
+ a.prefix === "xmlns" || a.name === "xmlns" || a.uri === ue || (r("attributeName", [a.uri ?? "", a.local ?? a.name]), r("attributeValue", [a.value]));
473
+ }
474
+ r("leaveStartTag", []);
475
+ }), this.parser.on("closetag", (n) => {
476
+ r("endTag", [n.uri ?? "", n.local ?? n.name]), this.depth = Math.max(0, this.depth - 1);
477
+ }), this.parser.on("text", (n) => {
478
+ this.depth > 0 && n.length > 0 && r("text", [n]);
479
+ }), this.parser.on("error", () => {
480
+ this.failed = !0;
481
+ });
482
+ }
483
+ /** Feed additional text (assumed to directly follow what's already fed). */
484
+ feed(t) {
485
+ try {
486
+ this.parser.write(t);
487
+ } catch {
488
+ }
489
+ this.prefix += t;
490
+ }
491
+ }
492
+ const he = 20, S = /* @__PURE__ */ new Map();
493
+ function O(e, t) {
494
+ if (S.delete(e), S.set(e, t), S.size > he) {
495
+ const r = S.keys().next().value;
496
+ r !== void 0 && S.delete(r);
497
+ }
498
+ }
499
+ function F(e, t, r) {
500
+ if (r) {
501
+ const s = S.get(r);
502
+ if (s && s.grammar === e && t.startsWith(s.prefix)) {
503
+ const a = t.slice(s.prefix.length);
504
+ return a.length > 0 && s.feed(a), O(r, s), s.walker;
505
+ }
506
+ }
507
+ const n = new fe(e);
508
+ return n.feed(t), r && O(r, n), n.walker;
509
+ }
510
+ function Se(e) {
511
+ e ? S.delete(e) : S.clear();
512
+ }
513
+ function q(e, t) {
514
+ const r = /* @__PURE__ */ new Set(), n = [];
515
+ for (const s of e) {
516
+ if (s.name !== t || !s.namePattern)
517
+ continue;
518
+ const a = s.namePattern.toArray?.(), l = a || (s.namePattern.toObject ? [s.namePattern.toObject()] : []);
519
+ for (const o of l) {
520
+ if (!o || typeof o.name != "string")
521
+ continue;
522
+ const d = `${o.ns ?? ""}:${o.name}`;
523
+ r.has(d) || (r.add(d), n.push(o));
524
+ }
525
+ }
526
+ return n;
527
+ }
528
+ function D(e, t, r) {
529
+ const n = t.toLowerCase();
530
+ return e.map((s) => ({ display: _(s.ns, s.name), doc: s.documentation })).filter((s) => s.display.toLowerCase().startsWith(n)).sort((s, a) => s.display.localeCompare(a.display)).map((s) => {
531
+ const a = {
532
+ label: s.display,
533
+ kind: r
534
+ };
535
+ return s.doc && (a.documentation = s.doc), a;
536
+ });
537
+ }
538
+ function de(e) {
539
+ const t = e.replace(/^<[\w.:-]*/, "");
540
+ let r = !1, n = "";
541
+ for (let a = 0; a < t.length; a++) {
542
+ const l = t[a];
543
+ r ? l === n && (r = !1) : (l === '"' || l === "'") && (r = !0, n = l);
544
+ }
545
+ return r ? null : e.match(/([A-Za-z_][\w.:-]*)?$/)?.[1] ?? "";
546
+ }
547
+ function ge(e) {
548
+ const t = [], r = /([A-Za-z_][\w.:-]*)\s*=\s*("([^"]*)"|'([^']*)')/g;
549
+ let n;
550
+ for (; (n = r.exec(e)) !== null; )
551
+ t.push({ name: n[1], value: n[3] ?? n[4] ?? "" });
552
+ return t;
553
+ }
554
+ function pe(e, t) {
555
+ let r = 0, n = 0;
556
+ for (; r < t.line; ) {
557
+ const s = e.indexOf(`
558
+ `, n);
559
+ if (s === -1)
560
+ return e.length;
561
+ n = s + 1, r++;
562
+ }
563
+ return Math.min(e.length, n + t.character);
564
+ }
565
+ export {
566
+ C as Severity,
567
+ K as applyRules,
568
+ Se as clearCompletionCache,
569
+ X as defaultFileReader,
570
+ M as defaultRuleset,
571
+ ke as getCompletions,
572
+ Ne as loadGrammarFromJSON,
573
+ H as relaxedRules,
574
+ ve as relaxedRuleset,
575
+ Q as resolveXIncludes,
576
+ ye as validateDocument
577
+ };
@@ -0,0 +1,34 @@
1
+ import { Diagnostic, DiagnosticSeverityValue, Rule, Ruleset, SchemaError } from './types';
2
+ /** Numeric DiagnosticSeverity values (mirrors vscode-languageserver-types). */
3
+ export declare const Severity: {
4
+ Error: DiagnosticSeverityValue;
5
+ Warning: DiagnosticSeverityValue;
6
+ Information: DiagnosticSeverityValue;
7
+ Hint: DiagnosticSeverityValue;
8
+ };
9
+ /**
10
+ * A small default ruleset. It mostly passes salve's errors through with a stable
11
+ * `code` and the `pretext` source, but rewrites the two most common structural
12
+ * errors into friendlier prose.
13
+ */
14
+ export declare const defaultRuleset: Ruleset;
15
+ /**
16
+ * Extra rules layered on top of the {@link defaultRuleset} in "relaxed"
17
+ * validation mode. Each entry suppresses a schema violation that PreTeXt authors
18
+ * commonly and legitimately hit but the stable schema does not (yet) permit.
19
+ *
20
+ * These are prepended before the generic pass-through rules so their `suppress`
21
+ * wins (rule matching stops at the first match). Add new relaxations here.
22
+ */
23
+ export declare const relaxedRules: Rule[];
24
+ /**
25
+ * The relaxed ruleset: the {@link defaultRuleset} with {@link relaxedRules}
26
+ * taking precedence, so the listed violations are silently ignored. Selected
27
+ * when the user opts into relaxed schema validation.
28
+ */
29
+ export declare const relaxedRuleset: Ruleset;
30
+ /**
31
+ * Turn raw {@link SchemaError}s into LSP {@link Diagnostic}s, applying the first
32
+ * matching rule's severity/message overrides and suppressions.
33
+ */
34
+ export declare function applyRules(errors: SchemaError[], ruleset?: Ruleset): Diagnostic[];