@traqula/rules-sparql-1-2 1.1.1 → 1.1.3

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.
@@ -1,11 +1,29 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.AstTransformer = void 0;
4
+ exports.sparql12CodepointEscape = sparql12CodepointEscape;
4
5
  exports.completeParseContext = completeParseContext;
5
6
  exports.completeGeneratorContext = completeGeneratorContext;
6
7
  exports.copyParseContext = copyParseContext;
7
8
  const core_1 = require("@traqula/core");
8
9
  const AstFactory_js_1 = require("./AstFactory.js");
10
+ /**
11
+ * Decode UCHAR codepoint escapes (\\uXXXX / \\UXXXXXXXX) within a string according to
12
+ * [SPARQL 1.2 §19.2](https://www.w3.org/TR/sparql12-query/#sec-escapes).
13
+ *
14
+ * Unlike the SPARQL 1.1 variant, this function rejects surrogate code points (U+D800–U+DFFF)
15
+ * even when they would form a valid surrogate pair.
16
+ */
17
+ function sparql12CodepointEscape(input) {
18
+ return input.replaceAll(/\\u([0-9a-fA-F]{4})|\\U([0-9a-fA-F]{8})/gu, (_, unicode4, unicode8) => {
19
+ const hex = (unicode4 ?? unicode8);
20
+ const codePoint = Number.parseInt(hex, 16);
21
+ if (codePoint >= 0xD800 && codePoint <= 0xDFFF) {
22
+ throw new Error(`Illegal codepoint escape: surrogate code point U+${hex.toUpperCase()}`);
23
+ }
24
+ return String.fromCodePoint(codePoint);
25
+ });
26
+ }
9
27
  function completeParseContext(context) {
10
28
  return {
11
29
  astFactory: context.astFactory ?? new AstFactory_js_1.AstFactory({ tracksSourceLocation: false }),
@@ -13,6 +31,7 @@ function completeParseContext(context) {
13
31
  prefixes: { ...context.prefixes },
14
32
  parseMode: context.parseMode ? new Set(context.parseMode) : new Set(['canParseVars', 'canCreateBlankNodes']),
15
33
  skipValidation: context.skipValidation ?? false,
34
+ codepointEscape: context.codepointEscape ?? sparql12CodepointEscape,
16
35
  };
17
36
  }
18
37
  function completeGeneratorContext(context) {
@@ -1 +1 @@
1
- {"version":3,"file":"parserUtils.js","sourceRoot":"","sources":["../../../lib/parserUtils.ts"],"names":[],"mappings":";;;AAKA,oDAUC;AAED,4DAWC;AAED,4CASC;AAvCD,wCAAmG;AACnG,mDAA6C;AAI7C,SAAgB,oBAAoB,CAClC,OAA+B;IAE/B,OAAO;QACL,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,IAAI,0BAAU,CAAC,EAAE,oBAAoB,EAAE,KAAK,EAAE,CAAC;QACjF,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,QAAQ,EAAE,EAAE,GAAG,OAAO,CAAC,QAAQ,EAAE;QACjC,SAAS,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAE,cAAc,EAAE,qBAAqB,CAAE,CAAC;QAC9G,cAAc,EAAE,OAAO,CAAC,cAAc,IAAI,KAAK;KAChD,CAAC;AACJ,CAAC;AAED,SAAgB,wBAAwB,CACtC,OAA8D;IAE9D,OAAO;QACL,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,IAAI,0BAAU,EAAE;QAClD,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,EAAE;QACpC,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,CAAC;QACjC,CAAC,yBAAkB,CAAC,EAAE,OAAO,CAAC,yBAAkB,CAAC,IAAI,CAAC;QACtD,CAAC,gCAAyB,CAAC,EAAE,OAAO,CAAC,gCAAyB,CAAC,IAAI,GAAG;KACvE,CAAC;AACJ,CAAC;AAED,SAAgB,gBAAgB,CAE9B,OAAU;IAEV,OAAO;QACL,GAAG,OAAO;QACV,QAAQ,EAAE,EAAE,GAAG,OAAO,CAAC,QAAQ,EAAE;QACjC,SAAS,EAAE,IAAI,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC;KACtC,CAAC;AACJ,CAAC;AAED,MAAa,cAAe,SAAQ,0BAAkC;CAAG;AAAzE,wCAAyE","sourcesContent":["import { TransformerSubTyped, traqulaIndentation, traqulaNewlineAlternative } from '@traqula/core';\nimport { AstFactory } from './AstFactory.js';\nimport type { SparqlContext, SparqlGeneratorContext } from './sparql12HelperTypes.js';\nimport type { Sparql12Nodes } from './sparql12Types.js';\n\nexport function completeParseContext(\n context: Partial<SparqlContext>,\n): SparqlContext {\n return {\n astFactory: context.astFactory ?? new AstFactory({ tracksSourceLocation: false }),\n baseIRI: context.baseIRI,\n prefixes: { ...context.prefixes },\n parseMode: context.parseMode ? new Set(context.parseMode) : new Set([ 'canParseVars', 'canCreateBlankNodes' ]),\n skipValidation: context.skipValidation ?? false,\n };\n}\n\nexport function completeGeneratorContext(\n context: Partial<SparqlGeneratorContext & { offset?: number }>,\n): SparqlGeneratorContext & { offset?: number } {\n return {\n astFactory: context.astFactory ?? new AstFactory(),\n origSource: context.origSource ?? '',\n offset: context.offset,\n indentInc: context.indentInc ?? 2,\n [traqulaIndentation]: context[traqulaIndentation] ?? 0,\n [traqulaNewlineAlternative]: context[traqulaNewlineAlternative] ?? ' ',\n };\n}\n\nexport function copyParseContext<T extends\nPartial<SparqlContext & SparqlGeneratorContext & { origSource: string; offset?: number }>>(\n context: T,\n): T {\n return {\n ...context,\n prefixes: { ...context.prefixes },\n parseMode: new Set(context.parseMode),\n };\n}\n\nexport class AstTransformer extends TransformerSubTyped<Sparql12Nodes> {}\n"]}
1
+ {"version":3,"file":"parserUtils.js","sourceRoot":"","sources":["../../../lib/parserUtils.ts"],"names":[],"mappings":";;;AAYA,0DAYC;AAED,oDAWC;AAED,4DAWC;AAED,4CASC;AA7DD,wCAAmG;AACnG,mDAA6C;AAI7C;;;;;;GAMG;AACH,SAAgB,uBAAuB,CAAC,KAAa;IACnD,OAAO,KAAK,CAAC,UAAU,CACrB,2CAA2C,EAC3C,CAAC,CAAC,EAAE,QAA4B,EAAE,QAA4B,EAAE,EAAE;QAChE,MAAM,GAAG,GAAG,CAAC,QAAQ,IAAI,QAAQ,CAAE,CAAC;QACpC,MAAM,SAAS,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QAC3C,IAAI,SAAS,IAAI,MAAM,IAAI,SAAS,IAAI,MAAM,EAAE,CAAC;YAC/C,MAAM,IAAI,KAAK,CAAC,oDAAoD,GAAG,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QAC3F,CAAC;QACD,OAAO,MAAM,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;IACzC,CAAC,CACF,CAAC;AACJ,CAAC;AAED,SAAgB,oBAAoB,CAClC,OAA+B;IAE/B,OAAO;QACL,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,IAAI,0BAAU,CAAC,EAAE,oBAAoB,EAAE,KAAK,EAAE,CAAC;QACjF,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,QAAQ,EAAE,EAAE,GAAG,OAAO,CAAC,QAAQ,EAAE;QACjC,SAAS,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAE,cAAc,EAAE,qBAAqB,CAAE,CAAC;QAC9G,cAAc,EAAE,OAAO,CAAC,cAAc,IAAI,KAAK;QAC/C,eAAe,EAAE,OAAO,CAAC,eAAe,IAAI,uBAAuB;KACpE,CAAC;AACJ,CAAC;AAED,SAAgB,wBAAwB,CACtC,OAA8D;IAE9D,OAAO;QACL,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,IAAI,0BAAU,EAAE;QAClD,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,EAAE;QACpC,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,CAAC;QACjC,CAAC,yBAAkB,CAAC,EAAE,OAAO,CAAC,yBAAkB,CAAC,IAAI,CAAC;QACtD,CAAC,gCAAyB,CAAC,EAAE,OAAO,CAAC,gCAAyB,CAAC,IAAI,GAAG;KACvE,CAAC;AACJ,CAAC;AAED,SAAgB,gBAAgB,CAE9B,OAAU;IAEV,OAAO;QACL,GAAG,OAAO;QACV,QAAQ,EAAE,EAAE,GAAG,OAAO,CAAC,QAAQ,EAAE;QACjC,SAAS,EAAE,IAAI,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC;KACtC,CAAC;AACJ,CAAC;AAED,MAAa,cAAe,SAAQ,0BAAkC;CAAG;AAAzE,wCAAyE","sourcesContent":["import { TransformerSubTyped, traqulaIndentation, traqulaNewlineAlternative } from '@traqula/core';\nimport { AstFactory } from './AstFactory.js';\nimport type { SparqlContext, SparqlGeneratorContext } from './sparql12HelperTypes.js';\nimport type { Sparql12Nodes } from './sparql12Types.js';\n\n/**\n * Decode UCHAR codepoint escapes (\\\\uXXXX / \\\\UXXXXXXXX) within a string according to\n * [SPARQL 1.2 §19.2](https://www.w3.org/TR/sparql12-query/#sec-escapes).\n *\n * Unlike the SPARQL 1.1 variant, this function rejects surrogate code points (U+D800–U+DFFF)\n * even when they would form a valid surrogate pair.\n */\nexport function sparql12CodepointEscape(input: string): string {\n return input.replaceAll(\n /\\\\u([0-9a-fA-F]{4})|\\\\U([0-9a-fA-F]{8})/gu,\n (_, unicode4: string | undefined, unicode8: string | undefined) => {\n const hex = (unicode4 ?? unicode8)!;\n const codePoint = Number.parseInt(hex, 16);\n if (codePoint >= 0xD800 && codePoint <= 0xDFFF) {\n throw new Error(`Illegal codepoint escape: surrogate code point U+${hex.toUpperCase()}`);\n }\n return String.fromCodePoint(codePoint);\n },\n );\n}\n\nexport function completeParseContext(\n context: Partial<SparqlContext>,\n): SparqlContext {\n return {\n astFactory: context.astFactory ?? new AstFactory({ tracksSourceLocation: false }),\n baseIRI: context.baseIRI,\n prefixes: { ...context.prefixes },\n parseMode: context.parseMode ? new Set(context.parseMode) : new Set([ 'canParseVars', 'canCreateBlankNodes' ]),\n skipValidation: context.skipValidation ?? false,\n codepointEscape: context.codepointEscape ?? sparql12CodepointEscape,\n };\n}\n\nexport function completeGeneratorContext(\n context: Partial<SparqlGeneratorContext & { offset?: number }>,\n): SparqlGeneratorContext & { offset?: number } {\n return {\n astFactory: context.astFactory ?? new AstFactory(),\n origSource: context.origSource ?? '',\n offset: context.offset,\n indentInc: context.indentInc ?? 2,\n [traqulaIndentation]: context[traqulaIndentation] ?? 0,\n [traqulaNewlineAlternative]: context[traqulaNewlineAlternative] ?? ' ',\n };\n}\n\nexport function copyParseContext<T extends\nPartial<SparqlContext & SparqlGeneratorContext & { origSource: string; offset?: number }>>(\n context: T,\n): T {\n return {\n ...context,\n prefixes: { ...context.prefixes },\n parseMode: new Set(context.parseMode),\n };\n}\n\nexport class AstTransformer extends TransformerSubTyped<Sparql12Nodes> {}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"sparql12HelperTypes.js","sourceRoot":"","sources":["../../../lib/sparql12HelperTypes.ts"],"names":[],"mappings":"","sourcesContent":["import type { GeneratorRule, ParserRule } from '@traqula/core';\nimport type * as T11 from '@traqula/rules-sparql-1-1';\nimport type { AstFactory } from './AstFactory.js';\n\nexport type SparqlRule<\n /**\n * Name of grammar rule, should be a strict subtype of string like 'myGrammarRule'.\n */\n NameType extends string = string,\n /**\n * Type that will be returned after a correct parse of this rule.\n * This type will be the return type of calling SUBRULE with this grammar rule.\n */\n ReturnType = unknown,\n GenInputType = ReturnType,\n /**\n * Function arguments that can be given to convey the state of the current parse operation.\n */\n ParamType extends any[] = [],\n> = SparqlGrammarRule<NameType, ReturnType, ParamType>\n & SparqlGeneratorRule<NameType, GenInputType, ParamType>;\n\nexport type SparqlGeneratorRule<\n /**\n * Name of grammar rule, should be a strict subtype of string like 'myGrammarRule'.\n */\n NameType extends string = string,\n /**\n * Type that will be returned after a correct parse of this rule.\n * This type will be the return type of calling SUBRULE with this grammar rule.\n */\n ReturnType = unknown,\n /**\n * Function arguments that can be given to convey the state of the current parse operation.\n */\n ParamType extends any [] = [],\n> = GeneratorRule<SparqlGeneratorContext, NameType, ReturnType, ParamType>;\n\nexport type SparqlGrammarRule<\n /**\n * Name of grammar rule, should be a strict subtype of string like 'myGrammarRule'.\n */\n NameType extends string = string,\n /**\n * Type that will be returned after a correct parse of this rule.\n * This type will be the return type of calling SUBRULE with this grammar rule.\n */\n ReturnType = unknown,\n /**\n * Function arguments that can be given to convey the state of the current parse operation.\n */\n ParamType extends any[] = [],\n> = ParserRule<SparqlContext, NameType, ReturnType, ParamType>;\n\nexport type SparqlContext = T11.SparqlContext & { astFactory: AstFactory };\nexport type SparqlGeneratorContext = T11.SparqlGeneratorContext & { astFactory: AstFactory };\n"]}
1
+ {"version":3,"file":"sparql12HelperTypes.js","sourceRoot":"","sources":["../../../lib/sparql12HelperTypes.ts"],"names":[],"mappings":"","sourcesContent":["import type { GeneratorRule, ParserRule } from '@traqula/core';\nimport type * as T11 from '@traqula/rules-sparql-1-1';\nimport type { AstFactory } from './AstFactory.js';\n\nexport type SparqlRule<\n /**\n * Name of grammar rule, should be a strict subtype of string like 'myGrammarRule'.\n */\n NameType extends string = string,\n /**\n * Type that will be returned after a correct parse of this rule.\n * This type will be the return type of calling SUBRULE with this grammar rule.\n */\n ReturnType = unknown,\n GenInputType = ReturnType,\n /**\n * Function arguments that can be given to convey the state of the current parse operation.\n */\n ParamType extends any[] = [],\n> = SparqlGrammarRule<NameType, ReturnType, ParamType>\n & SparqlGeneratorRule<NameType, GenInputType, ParamType>;\n\nexport type SparqlGeneratorRule<\n /**\n * Name of grammar rule, should be a strict subtype of string like 'myGrammarRule'.\n */\n NameType extends string = string,\n /**\n * Type that will be returned after a correct parse of this rule.\n * This type will be the return type of calling SUBRULE with this grammar rule.\n */\n ReturnType = unknown,\n /**\n * Function arguments that can be given to convey the state of the current parse operation.\n */\n ParamType extends any [] = [],\n> = GeneratorRule<SparqlGeneratorContext, NameType, ReturnType, ParamType>;\n\nexport type SparqlGrammarRule<\n /**\n * Name of grammar rule, should be a strict subtype of string like 'myGrammarRule'.\n */\n NameType extends string = string,\n /**\n * Type that will be returned after a correct parse of this rule.\n * This type will be the return type of calling SUBRULE with this grammar rule.\n */\n ReturnType = unknown,\n /**\n * Function arguments that can be given to convey the state of the current parse operation.\n */\n ParamType extends any[] = [],\n> = ParserRule<SparqlContext, NameType, ReturnType, ParamType>;\n\nexport type SparqlContext = T11.SparqlContext & {\n astFactory: AstFactory;\n /**\n * Function that decodes UCHAR codepoint escapes (\\\\uXXXX / \\\\UXXXXXXXX) within a string.\n * In SPARQL 1.2 this is applied per-rule rather than as a query pre-processor.\n */\n codepointEscape: (input: string) => string;\n};\nexport type SparqlGeneratorContext = T11.SparqlGeneratorContext & { astFactory: AstFactory };\n"]}
@@ -2,6 +2,8 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.langTagHasCorrectRange = langTagHasCorrectRange;
4
4
  exports.findPatternBoundedVars = findPatternBoundedVars;
5
+ exports.queryProjectionIsGood = queryProjectionIsGood;
6
+ const rules_sparql_1_1_1 = require("@traqula/rules-sparql-1-1");
5
7
  const AstFactory_js_1 = require("./AstFactory.js");
6
8
  const F = new AstFactory_js_1.AstFactory();
7
9
  function isLangDir(dir) {
@@ -96,4 +98,77 @@ function findPatternBoundedVars(iter, boundedVars) {
96
98
  }
97
99
  }
98
100
  }
101
+ /**
102
+ * Verify that the projected variables (select head) are allowed:
103
+ * - no group-by on select *
104
+ * - if group-by, selected variables need to be collected by the group-by
105
+ * - 'select ?var as ?other', ?other cannot be in scope
106
+ */
107
+ function queryProjectionIsGood(query) {
108
+ // NoGroupByOnWildcardSelect
109
+ if (query.variables.length === 1 && F.isWildcard(query.variables[0])) {
110
+ if (query.solutionModifiers.group !== undefined) {
111
+ throw new Error('GROUP BY not allowed with wildcard');
112
+ }
113
+ return;
114
+ }
115
+ // CannotProjectUngroupedVars - can be skipped if `SELECT *`
116
+ // Check for projection of ungrouped variable
117
+ // Check can be skipped in case of wildcard select.
118
+ const variables = query.variables;
119
+ const hasCountAggregate = variables.flatMap(varVal => F.isTerm(varVal) ? [] : (0, rules_sparql_1_1_1.getAggregatesOfExpression)(varVal.expression)).some(agg => agg.aggregation === 'count' && !agg.expression.some(arg => F.isWildcard(arg)));
120
+ const groupBy = query.solutionModifiers.group;
121
+ if (hasCountAggregate || groupBy) {
122
+ // We have to check whether
123
+ // 1. Variables used in projection are usable given the group by clause
124
+ // 2. A selectCount will create an implicit group by clause.
125
+ // Variables bound by preceding (expr AS ?var) expressions are in scope for later expressions.
126
+ const asBoundVars = new Set();
127
+ for (const selectVar of variables) {
128
+ if (F.isTerm(selectVar)) {
129
+ if (!groupBy || !groupBy.groupings.map(groupvar => (0, rules_sparql_1_1_1.getExpressionId)(groupvar))
130
+ .includes(((0, rules_sparql_1_1_1.getExpressionId)(selectVar)))) {
131
+ throw new Error('Variable not allowed in projection');
132
+ }
133
+ }
134
+ else if ((0, rules_sparql_1_1_1.getAggregatesOfExpression)(selectVar.expression).length === 0) {
135
+ // Current value binding does not use aggregates
136
+ const usedvars = new Set();
137
+ (0, rules_sparql_1_1_1.getVariablesFromExpression)(selectVar.expression, usedvars);
138
+ for (const usedvar of usedvars) {
139
+ // If the var is created within the select, it is fine.
140
+ if (asBoundVars.has(usedvar)) {
141
+ continue;
142
+ }
143
+ if (!groupBy || !groupBy.groupings.map(groupVar => (0, rules_sparql_1_1_1.getExpressionId)(groupVar)).includes(usedvar)) {
144
+ throw new Error(`Use of ungrouped variable in projection of operation (?${usedvar})`);
145
+ }
146
+ }
147
+ }
148
+ if (!F.isTerm(selectVar)) {
149
+ // Register a var is created by a bind
150
+ asBoundVars.add(selectVar.variable.value);
151
+ }
152
+ }
153
+ }
154
+ // NOTE 12: Check if id of each AS-selected column is not yet bound by subquery
155
+ const subqueries = query.where.patterns.filter(pattern => pattern.type === 'query');
156
+ if (subqueries.length > 0) {
157
+ const selectBoundedVars = new Set();
158
+ for (const variable of variables) {
159
+ if ('variable' in variable) {
160
+ selectBoundedVars.add(variable.variable.value);
161
+ }
162
+ }
163
+ // Look at in scope variables
164
+ const vars = subqueries.flatMap(sub => sub.variables)
165
+ .map(v => F.isTerm(v) ? v.value : (F.isWildcard(v) ? '*' : v.variable.value));
166
+ const subqueryIds = new Set(vars);
167
+ for (const selectedVarId of selectBoundedVars) {
168
+ if (subqueryIds.has(selectedVarId)) {
169
+ throw new Error(`Target id of 'AS' (?${selectedVarId}) already used in subquery`);
170
+ }
171
+ }
172
+ }
173
+ }
99
174
  //# sourceMappingURL=validators.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"validators.js","sourceRoot":"","sources":["../../../lib/validators.ts"],"names":[],"mappings":"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","sourcesContent":["import { AstFactory } from './AstFactory.js';\nimport type {\n Path,\n Pattern,\n SparqlQuery,\n Term,\n TermLiteral,\n TripleCollection,\n TripleNesting,\n Wildcard,\n} from './sparql12Types.js';\n\nconst F = new AstFactory();\n\nfunction isLangDir(dir: string): dir is 'ltr' | 'rtl' {\n return dir === 'ltr' || dir === 'rtl';\n}\n\nexport function langTagHasCorrectRange(literal: TermLiteral): void {\n if (F.isTermLiteralLangStr(literal)) {\n const dirSplit = literal.langOrIri.split('--');\n if (dirSplit.length > 1) {\n const [ _, direction ] = dirSplit;\n if (!isLangDir(direction)) {\n throw new Error(`language direction \"${direction}\" of literal \"${JSON.stringify(literal)}\" is not is required range 'ltr' | 'rtl'.`);\n }\n }\n }\n}\n\nexport function findPatternBoundedVars(\n iter: SparqlQuery | Pattern | TripleNesting | TripleCollection | Path | Term | Wildcard,\n boundedVars: Set<string>,\n): void {\n if (F.isQuery(iter) || F.isUpdate(iter)) {\n if (F.isQuerySelect(iter) || F.isQueryDescribe(iter)) {\n if (iter.where && iter.variables.some(x => F.isWildcard(x))) {\n findPatternBoundedVars(iter.where, boundedVars);\n } else {\n for (const v of iter.variables) {\n findPatternBoundedVars(v, boundedVars);\n }\n }\n if (iter.solutionModifiers.group) {\n const grouping = iter.solutionModifiers.group;\n for (const g of grouping.groupings) {\n if ('variable' in g) {\n findPatternBoundedVars(g.variable, boundedVars);\n }\n }\n }\n if (iter.values?.values && iter.values.values.length > 0) {\n const values = iter.values.values;\n for (const v of Object.keys(values[0])) {\n boundedVars.add(v);\n }\n }\n }\n } else if (F.isTerm(iter)) {\n if (F.isTermVariable(iter)) {\n boundedVars.add(iter.value);\n }\n if (F.isTermTriple(iter)) {\n findPatternBoundedVars(iter.subject, boundedVars);\n findPatternBoundedVars(iter.predicate, boundedVars);\n findPatternBoundedVars(iter.object, boundedVars);\n }\n } else if (F.isTriple(iter)) {\n findPatternBoundedVars(iter.subject, boundedVars);\n findPatternBoundedVars(iter.predicate, boundedVars);\n findPatternBoundedVars(iter.object, boundedVars);\n for (const annotation of iter.annotations ?? []) {\n findPatternBoundedVars(\n F.isTripleCollection(annotation) ? annotation : annotation.val,\n boundedVars,\n );\n }\n } else if (F.isPath(iter)) {\n for (const item of iter.items) {\n findPatternBoundedVars(item, boundedVars);\n }\n } else if (F.isTripleCollection(iter) || F.isPatternBgp(iter)) {\n for (const triple of iter.triples) {\n findPatternBoundedVars(triple, boundedVars);\n }\n } else if (\n F.isPatternGroup(iter) || F.isPatternUnion(iter) || F.isPatternOptional(iter) || F.isPatternService(iter)) {\n for (const pattern of iter.patterns) {\n findPatternBoundedVars(pattern, boundedVars);\n }\n if (F.isPatternService(iter)) {\n findPatternBoundedVars(iter.name, boundedVars);\n }\n } else if (F.isPatternBind(iter)) {\n findPatternBoundedVars(iter.variable, boundedVars);\n } else if (F.isPatternValues(iter)) {\n for (const variable of Object.keys(iter.values.at(0) ?? {})) {\n boundedVars.add(variable);\n }\n } else if (F.isPatternGraph(iter)) {\n findPatternBoundedVars(iter.name, boundedVars);\n for (const pattern of iter.patterns) {\n findPatternBoundedVars(pattern, boundedVars);\n }\n }\n}\n"]}
1
+ {"version":3,"file":"validators.js","sourceRoot":"","sources":["../../../lib/validators.ts"],"names":[],"mappings":"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","sourcesContent":["import { getAggregatesOfExpression, getExpressionId, getVariablesFromExpression } from '@traqula/rules-sparql-1-1';\nimport type * as T11 from '@traqula/rules-sparql-1-1';\nimport { AstFactory } from './AstFactory.js';\nimport type {\n Path,\n Pattern,\n PatternBind,\n QuerySelect,\n SparqlQuery,\n Term,\n TermLiteral,\n TermVariable,\n TripleCollection,\n TripleNesting,\n Wildcard,\n} from './sparql12Types.js';\n\nconst F = new AstFactory();\n\nfunction isLangDir(dir: string): dir is 'ltr' | 'rtl' {\n return dir === 'ltr' || dir === 'rtl';\n}\n\nexport function langTagHasCorrectRange(literal: TermLiteral): void {\n if (F.isTermLiteralLangStr(literal)) {\n const dirSplit = literal.langOrIri.split('--');\n if (dirSplit.length > 1) {\n const [ _, direction ] = dirSplit;\n if (!isLangDir(direction)) {\n throw new Error(`language direction \"${direction}\" of literal \"${JSON.stringify(literal)}\" is not is required range 'ltr' | 'rtl'.`);\n }\n }\n }\n}\n\nexport function findPatternBoundedVars(\n iter: SparqlQuery | Pattern | TripleNesting | TripleCollection | Path | Term | Wildcard,\n boundedVars: Set<string>,\n): void {\n if (F.isQuery(iter) || F.isUpdate(iter)) {\n if (F.isQuerySelect(iter) || F.isQueryDescribe(iter)) {\n if (iter.where && iter.variables.some(x => F.isWildcard(x))) {\n findPatternBoundedVars(iter.where, boundedVars);\n } else {\n for (const v of iter.variables) {\n findPatternBoundedVars(v, boundedVars);\n }\n }\n if (iter.solutionModifiers.group) {\n const grouping = iter.solutionModifiers.group;\n for (const g of grouping.groupings) {\n if ('variable' in g) {\n findPatternBoundedVars(g.variable, boundedVars);\n }\n }\n }\n if (iter.values?.values && iter.values.values.length > 0) {\n const values = iter.values.values;\n for (const v of Object.keys(values[0])) {\n boundedVars.add(v);\n }\n }\n }\n } else if (F.isTerm(iter)) {\n if (F.isTermVariable(iter)) {\n boundedVars.add(iter.value);\n }\n if (F.isTermTriple(iter)) {\n findPatternBoundedVars(iter.subject, boundedVars);\n findPatternBoundedVars(iter.predicate, boundedVars);\n findPatternBoundedVars(iter.object, boundedVars);\n }\n } else if (F.isTriple(iter)) {\n findPatternBoundedVars(iter.subject, boundedVars);\n findPatternBoundedVars(iter.predicate, boundedVars);\n findPatternBoundedVars(iter.object, boundedVars);\n for (const annotation of iter.annotations ?? []) {\n findPatternBoundedVars(\n F.isTripleCollection(annotation) ? annotation : annotation.val,\n boundedVars,\n );\n }\n } else if (F.isPath(iter)) {\n for (const item of iter.items) {\n findPatternBoundedVars(item, boundedVars);\n }\n } else if (F.isTripleCollection(iter) || F.isPatternBgp(iter)) {\n for (const triple of iter.triples) {\n findPatternBoundedVars(triple, boundedVars);\n }\n } else if (\n F.isPatternGroup(iter) || F.isPatternUnion(iter) || F.isPatternOptional(iter) || F.isPatternService(iter)) {\n for (const pattern of iter.patterns) {\n findPatternBoundedVars(pattern, boundedVars);\n }\n if (F.isPatternService(iter)) {\n findPatternBoundedVars(iter.name, boundedVars);\n }\n } else if (F.isPatternBind(iter)) {\n findPatternBoundedVars(iter.variable, boundedVars);\n } else if (F.isPatternValues(iter)) {\n for (const variable of Object.keys(iter.values.at(0) ?? {})) {\n boundedVars.add(variable);\n }\n } else if (F.isPatternGraph(iter)) {\n findPatternBoundedVars(iter.name, boundedVars);\n for (const pattern of iter.patterns) {\n findPatternBoundedVars(pattern, boundedVars);\n }\n }\n}\n\n/**\n * Verify that the projected variables (select head) are allowed:\n * - no group-by on select *\n * - if group-by, selected variables need to be collected by the group-by\n * - 'select ?var as ?other', ?other cannot be in scope\n */\nexport function queryProjectionIsGood(query: Pick<QuerySelect, 'variables' | 'solutionModifiers' | 'where'>): void {\n // NoGroupByOnWildcardSelect\n if (query.variables.length === 1 && F.isWildcard(query.variables[0])) {\n if (query.solutionModifiers.group !== undefined) {\n throw new Error('GROUP BY not allowed with wildcard');\n }\n return;\n }\n\n // CannotProjectUngroupedVars - can be skipped if `SELECT *`\n // Check for projection of ungrouped variable\n // Check can be skipped in case of wildcard select.\n const variables = <Exclude<typeof query.variables, [Wildcard]>> query.variables;\n const hasCountAggregate = variables.flatMap(\n varVal => F.isTerm(varVal) ? [] : getAggregatesOfExpression(<T11.Expression> varVal.expression),\n ).some(agg => agg.aggregation === 'count' && !agg.expression.some(arg => F.isWildcard(arg)));\n const groupBy = query.solutionModifiers.group;\n if (hasCountAggregate || groupBy) {\n // We have to check whether\n // 1. Variables used in projection are usable given the group by clause\n // 2. A selectCount will create an implicit group by clause.\n // Variables bound by preceding (expr AS ?var) expressions are in scope for later expressions.\n const asBoundVars = new Set<string>();\n for (const selectVar of variables) {\n if (F.isTerm(selectVar)) {\n if (!groupBy || !groupBy.groupings.map(groupvar =>\n getExpressionId(<T11.Expression | T11.SolutionModifierGroupBind> groupvar))\n .includes((getExpressionId(selectVar)))) {\n throw new Error('Variable not allowed in projection');\n }\n } else if (getAggregatesOfExpression(<T11.Expression> selectVar.expression).length === 0) {\n // Current value binding does not use aggregates\n const usedvars = new Set<string>();\n getVariablesFromExpression(<T11.Expression> selectVar.expression, usedvars);\n for (const usedvar of usedvars) {\n // If the var is created within the select, it is fine.\n if (asBoundVars.has(usedvar)) {\n continue;\n }\n if (!groupBy || !groupBy.groupings.map(groupVar =>\n getExpressionId(<T11.Expression | T11.SolutionModifierGroupBind>groupVar)).includes(usedvar)) {\n throw new Error(`Use of ungrouped variable in projection of operation (?${usedvar})`);\n }\n }\n }\n if (!F.isTerm(selectVar)) {\n // Register a var is created by a bind\n asBoundVars.add(selectVar.variable.value);\n }\n }\n }\n\n // NOTE 12: Check if id of each AS-selected column is not yet bound by subquery\n const subqueries = query.where.patterns.filter(pattern => pattern.type === 'query');\n if (subqueries.length > 0) {\n const selectBoundedVars = new Set<string>();\n for (const variable of variables) {\n if ('variable' in variable) {\n selectBoundedVars.add(variable.variable.value);\n }\n }\n\n // Look at in scope variables\n const vars = subqueries.flatMap<TermVariable | PatternBind | Wildcard>(sub => sub.variables)\n .map(v => F.isTerm(v) ? v.value : (F.isWildcard(v) ? '*' : v.variable.value));\n const subqueryIds = new Set(vars);\n for (const selectedVarId of selectBoundedVars) {\n if (subqueryIds.has(selectedVarId)) {\n throw new Error(`Target id of 'AS' (?${selectedVarId}) already used in subquery`);\n }\n }\n }\n}\n"]}
@@ -8,11 +8,16 @@ import type { RuleDefReturn, Wrap } from '@traqula/core';
8
8
  import { gram as S11 } from '@traqula/rules-sparql-1-1';
9
9
  import type * as T11 from '@traqula/rules-sparql-1-1';
10
10
  import type { SparqlGeneratorRule, SparqlGrammarRule, SparqlRule } from './sparql12HelperTypes.js';
11
- import type { Annotation, ContextDefinition, ContextDefinitionVersion, Expression, GraphNode, GraphTerm, PatternBgp, Term, TermBlank, TermIri, TermLiteral, TermTriple, TermVariable, TripleCollectionReifiedTriple, TripleNesting } from './sparql12Types.js';
11
+ import type { Annotation, ContextDefinition, ContextDefinitionVersion, Expression, GraphNode, GraphTerm, PatternBgp, QuerySelect, Term, TermBlank, TermIri, TermLiteral, TermTriple, TermVariable, TripleCollectionReifiedTriple, TripleNesting } from './sparql12Types.js';
12
12
  /**
13
13
  *[[7]](https://www.w3.org/TR/sparql12-query/#rVersionDecl)
14
14
  */
15
15
  export declare const versionDecl: SparqlRule<'versionDecl', ContextDefinitionVersion>;
16
+ /**
17
+ * [[9]](https://www.w3.org/TR/sparql12-query/#rSelectQuery)
18
+ * (Validator has changed: https://github.com/w3c/sparql-query/pull/380)
19
+ */
20
+ export declare const selectQuery: SparqlGrammarRule<'selectQuery', Omit<QuerySelect, 'type' | 'context' | 'values'>>;
16
21
  /**
17
22
  * [[8]](https://www.w3.org/TR/sparql12-query/#rVersionSpecifier)
18
23
  */
@@ -179,6 +184,24 @@ export declare const builtInCall: typeof S11.builtInCall;
179
184
  * [[149]](https://www.w3.org/TR/sparql12-query/#rRDFLiteral)
180
185
  */
181
186
  export declare const rdfLiteral: SparqlGrammarRule<'rdfLiteral', RuleDefReturn<typeof S11.rdfLiteral>>;
187
+ /**
188
+ * OVERRIDING RULE: {@link S11.string}.
189
+ * [[155]](https://www.w3.org/TR/sparql12-query/#rString)
190
+ *
191
+ * Uses the SPARQL 1.2 string tokens (which include UCHAR in their patterns).
192
+ * Applies two-pass decoding per the SPARQL 1.2 spec: UCHAR first (via
193
+ * {@link SparqlContext.codepointEscape}), then ECHAR. This order ensures that
194
+ * `\\u0041` yields `\A` (→ invalid ECHAR) rather than `\u0041` (single-pass result).
195
+ */
196
+ export declare const string: SparqlGrammarRule<'string', T11.TermLiteralStr>;
197
+ /**
198
+ * OVERRIDING RULE: {@link S11.iriFull}.
199
+ * [[160]](https://www.w3.org/TR/sparql12-query/#rIRIREF)
200
+ *
201
+ * Uses the SPARQL 1.2 IRI token (which includes UCHAR in its pattern) and applies
202
+ * codepoint escape decoding via {@link SparqlContext.codepointEscape}.
203
+ */
204
+ export declare const iriFull: SparqlGrammarRule<'iriFull', T11.TermIriFull>;
182
205
  export declare const unaryExpression: SparqlGrammarRule<(typeof S11.unaryExpression)['name'], Expression>;
183
206
  /**
184
207
  * OVERRIDING RULE: {@link S11.triplesBlock}.
@@ -1,7 +1,7 @@
1
1
  import { traqulaIndentation } from '@traqula/core';
2
2
  import { CommonIRIs, funcExpr1, funcExpr3, gram as S11, lex as l11 } from '@traqula/rules-sparql-1-1';
3
3
  import * as l12 from './lexer.js';
4
- import { langTagHasCorrectRange } from './validators.js';
4
+ import { langTagHasCorrectRange, queryProjectionIsGood } from './validators.js';
5
5
  /**
6
6
  *[[7]](https://www.w3.org/TR/sparql12-query/#rVersionDecl)
7
7
  */
@@ -18,6 +18,33 @@ export const versionDecl = {
18
18
  });
19
19
  },
20
20
  };
21
+ /**
22
+ * [[9]](https://www.w3.org/TR/sparql12-query/#rSelectQuery)
23
+ * (Validator has changed: https://github.com/w3c/sparql-query/pull/380)
24
+ */
25
+ export const selectQuery = {
26
+ name: 'selectQuery',
27
+ impl: ({ ACTION, SUBRULE }) => (C) => {
28
+ const selectVal = SUBRULE(S11.selectClause);
29
+ const from = SUBRULE(S11.datasetClauseStar);
30
+ const where = SUBRULE(S11.whereClause);
31
+ const modifiers = SUBRULE(S11.solutionModifier);
32
+ return ACTION(() => {
33
+ const ret = {
34
+ subType: 'select',
35
+ where: where.val,
36
+ solutionModifiers: modifiers,
37
+ datasets: from,
38
+ ...selectVal.val,
39
+ loc: C.astFactory.sourceLocation(selectVal, where, modifiers.group, modifiers.having, modifiers.order, modifiers.limitOffset),
40
+ };
41
+ if (!C.skipValidation) {
42
+ queryProjectionIsGood(ret);
43
+ }
44
+ return ret;
45
+ });
46
+ },
47
+ };
21
48
  /**
22
49
  * [[8]](https://www.w3.org/TR/sparql12-query/#rVersionSpecifier)
23
50
  */
@@ -25,8 +52,8 @@ export const versionSpecifier = {
25
52
  name: 'versionSpecifier',
26
53
  impl: ({ ACTION, CONSUME, OR }) => (C) => {
27
54
  const token = OR([
28
- { ALT: () => CONSUME(l11.terminals.stringLiteral1) },
29
- { ALT: () => CONSUME(l11.terminals.stringLiteral2) },
55
+ { ALT: () => CONSUME(l12.stringLiteral1) },
56
+ { ALT: () => CONSUME(l12.stringLiteral2) },
30
57
  ]);
31
58
  return ACTION(() => C.astFactory.wrap(token.image.slice(1, -1), C.astFactory.sourceLocation(token)));
32
59
  },
@@ -575,6 +602,86 @@ export const rdfLiteral = {
575
602
  ])) ?? value;
576
603
  },
577
604
  };
605
+ /**
606
+ * OVERRIDING RULE: {@link S11.string}.
607
+ * [[155]](https://www.w3.org/TR/sparql12-query/#rString)
608
+ *
609
+ * Uses the SPARQL 1.2 string tokens (which include UCHAR in their patterns).
610
+ * Applies two-pass decoding per the SPARQL 1.2 spec: UCHAR first (via
611
+ * {@link SparqlContext.codepointEscape}), then ECHAR. This order ensures that
612
+ * `\\u0041` yields `\A` (→ invalid ECHAR) rather than `\u0041` (single-pass result).
613
+ */
614
+ export const string = {
615
+ name: 'string',
616
+ impl: ({ ACTION, CONSUME, OR }) => (C) => {
617
+ const tuple = OR([
618
+ { ALT: () => {
619
+ const token = CONSUME(l12.stringLiteral1);
620
+ return [token, token.image.slice(1, -1)];
621
+ } },
622
+ { ALT: () => {
623
+ const token = CONSUME(l12.stringLiteral2);
624
+ return [token, token.image.slice(1, -1)];
625
+ } },
626
+ { ALT: () => {
627
+ const token = CONSUME(l12.stringLiteralLong1);
628
+ return [token, token.image.slice(3, -3)];
629
+ } },
630
+ { ALT: () => {
631
+ const token = CONSUME(l12.stringLiteralLong2);
632
+ return [token, token.image.slice(3, -3)];
633
+ } },
634
+ ]);
635
+ return ACTION(() => {
636
+ const [token, raw] = tuple;
637
+ const F = C.astFactory;
638
+ // Pass 1: Decode all UCHAR escape sequences (and reject surrogate code points).
639
+ const afterUchar = C.codepointEscape(raw);
640
+ // Pass 2: Validate and decode ECHAR sequences in the UCHAR-decoded string.
641
+ const ecmap = {
642
+ t: '\t',
643
+ n: '\n',
644
+ r: '\r',
645
+ b: '\b',
646
+ f: '\f',
647
+ '"': '"',
648
+ '\'': '\'',
649
+ '\\': '\\',
650
+ };
651
+ const value = afterUchar.replaceAll(/\\(.?)/gsu, (_, char) => {
652
+ if (!char) {
653
+ throw new Error(`String literal ends with an unpaired backslash`);
654
+ }
655
+ if (!(char in ecmap)) {
656
+ throw new Error(`Invalid escape sequence \\${char} in string literal`);
657
+ }
658
+ return ecmap[char];
659
+ });
660
+ // Catch literal surrogate code units embedded directly in the query (not via \uXXXX).
661
+ if (/[\uD800-\uDBFF](?:[^\uDC00-\uDFFF]|$)/u.test(value)) {
662
+ throw new Error(`Invalid unicode codepoint of surrogate pair without corresponding codepoint`);
663
+ }
664
+ return F.termLiteral(F.sourceLocation(token), value);
665
+ });
666
+ },
667
+ };
668
+ /**
669
+ * OVERRIDING RULE: {@link S11.iriFull}.
670
+ * [[160]](https://www.w3.org/TR/sparql12-query/#rIRIREF)
671
+ *
672
+ * Uses the SPARQL 1.2 IRI token (which includes UCHAR in its pattern) and applies
673
+ * codepoint escape decoding via {@link SparqlContext.codepointEscape}.
674
+ */
675
+ export const iriFull = {
676
+ name: 'iriFull',
677
+ impl: ({ ACTION, CONSUME }) => (C) => {
678
+ const iriToken = CONSUME(l12.iriRef);
679
+ return ACTION(() => {
680
+ const raw = iriToken.image.slice(1, -1);
681
+ return C.astFactory.termNamed(C.astFactory.sourceLocation(iriToken), C.codepointEscape(raw));
682
+ });
683
+ },
684
+ };
578
685
  export const unaryExpression = {
579
686
  name: 'unaryExpression',
580
687
  impl: ({ ACTION, CONSUME, SUBRULE1, SUBRULE2, OR1, OR2 }) => C => OR1([