Skip to content

Commit

Permalink
bugfix: note 13 check
Browse files Browse the repository at this point in the history
  • Loading branch information
jitsedesmet committed Jan 10, 2025
1 parent 4d2f9b8 commit c52eebd
Show file tree
Hide file tree
Showing 12 changed files with 667 additions and 36 deletions.
27 changes: 23 additions & 4 deletions esbuild.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const plugins = [{
},
}];

const ctx = await esbuild.context({
const srcCtx = await esbuild.context({
entryPoints: [ 'src/index.ts' ],
outdir: 'out',
outExtension: {
Expand All @@ -42,9 +42,28 @@ const ctx = await esbuild.context({
plugins,
});

const specCtx = await esbuild.context({
entryPoints: [ 'spec/parser.ts' ],
outfile: 'out/parser.cjs',
outExtension: {
'.js': '.cjs',
},
bundle: true,
target: 'ES2020',
format: 'cjs',
loader: { '.ts': 'ts' },
platform: 'node',
sourcemap: !minify,
minify,
plugins,
});

if (watch) {
await ctx.watch();
await srcCtx.watch();
await specCtx.watch();
} else {
await ctx.rebuild();
ctx.dispose();
await srcCtx.rebuild();
srcCtx.dispose();
await specCtx.rebuild();
specCtx.dispose();
}
14 changes: 12 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,16 @@
"build & run ESM": "yarn build && node src/index.js",
"build & run CJS": "yarn build && node out/index.cjs",
"test": "yarn build && vitest test --run",
"bench": "yarn build && vitest bench --run"
"bench": "yarn build && vitest bench --run",
"spec:base": "rdf-test-suite out/parser.cjs http://w3c.github.io/rdf-tests/sparql/sparql11/manifest-all.ttl -c .rdf-test-suite-cache/",
"spec:query": "npm run spec:base -- -s http://www.w3.org/TR/sparql11-query/",
"spec:update": "npm run spec:base -- -s http://www.w3.org/TR/sparql11-update/",
"spec:star": "rdf-test-suite spec/parser.js https://w3c.github.io/rdf-star/tests/sparql/syntax/manifest.jsonld -i '{ \"sparqlStar\": true }' -c .rdf-test-suite-cache/",
"spec:earl:query": "npm run spec:query --silent -- -o earl -p spec/earl-meta.json > spec/earl-query.ttl",
"spec:earl:update": "npm run spec:update --silent -- -o earl -p spec/earl-meta.json > spec/earl-update.ttl",
"spec:earl:star": "npm run spec:star --silent -- -o earl -p spec/earl-meta.json > spec/earl-star.ttl",
"spec:all": "npm run spec:base && npm run spec:query && npm run spec:update && npm run spec:star",
"spec:earl": "npm run spec:earl:query && npm run spec:earl:update && npm run spec:earl:star"
},
"dependencies": {
"chevrotain": "^11.0.3",
Expand All @@ -34,6 +43,7 @@
"sparqljs": "^3.7.3",
"ts-jest": "^29.2.5",
"typescript": "^5.3.3",
"vitest": "^2.1.8"
"vitest": "^2.1.8",
"rdf-test-suite": "^2.0.0"
}
}
22 changes: 22 additions & 0 deletions spec/earl-meta.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"applicationBugsUrl": "https://github.com/jitsedesmet/traqula/issues",
"applicationDescription": "A transpiler for the SPARQL query language in TypeScript.",
"applicationNameFull": "traqula",
"applicationNameNpm": "traqula",
"applicationHomepageUrl": "https://github.com/jitsedesmet/traqula",
"applicationUri": "https://www.npmjs.com/package/traqula/",
"authors": [
{
"homepage": "https://jitsedesmet.be/",
"name": "Jitse De Smet <[email protected]>",
"uri": "https://jitsedesmet.be/profile/#me"
}
],
"licenseUri": "http://opensource.org/licenses/MIT",
"reportUri": null,
"specificationUris": [
"http://www.w3.org/TR/sparql11-query/",
"http://www.w3.org/TR/sparql11-update/",
"https://www.w3.org/TR/sparql12-query/"
]
}
14 changes: 14 additions & 0 deletions spec/parser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { ErrorSkipped, } from 'rdf-test-suite';
import { Sparql11Parser } from '../src'

export async function parse(query: string, baseIRI: string) {
const parser = new Sparql11Parser({ baseIRI });
parser.parse(query);
}
export function query() {
return Promise.reject(new ErrorSkipped('Querying is not supported'));
}

export function update() {
return Promise.reject(new ErrorSkipped('Updating is not supported'));
}
6 changes: 5 additions & 1 deletion src/grammar/sparql11/literals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,11 @@ export const prefixedName: RuleDef<'prefixedName', IriTerm> = <const> {
]);
return ACTION(() => {
const [ prefix, localName ] = fullStr.split(':');
return context.dataFactory.namedNode(context.prefixes[prefix] + localName);
const value = prefix ? context.prefixes[prefix] : prefix;
if (value === undefined) {
throw new Error(`Unknown prefix: ${prefix}`);
}
return context.dataFactory.namedNode(resolveIRI(value + localName, context.baseIRI));
});
},
};
Expand Down
32 changes: 16 additions & 16 deletions src/grammar/sparql11/whereClause.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,23 +62,21 @@ export const groupGraphPattern: RuleDef<'groupGraphPattern', GroupPattern> = <co
};

function findBoundVarsFromGroupGraphPattern(pattern: Pattern, boundedVars: Set<string>): void {
if (pattern.type === 'group' || pattern.type === 'bgp') {
if ('triples' in pattern) {
for (const triple of pattern.triples) {
if (isVariable(triple.subject)) {
boundedVars.add(triple.subject.value);
}
if (isVariable(triple.predicate)) {
boundedVars.add(triple.predicate.value);
}
if (isVariable(triple.object)) {
boundedVars.add(triple.object.value);
}
if ('triples' in pattern) {
for (const triple of pattern.triples) {
if (isVariable(triple.subject)) {
boundedVars.add(triple.subject.value);
}
} else if ('patterns' in pattern) {
for (const pat of pattern.patterns) {
findBoundVarsFromGroupGraphPattern(pat, boundedVars);
if (isVariable(triple.predicate)) {
boundedVars.add(triple.predicate.value);
}
if (isVariable(triple.object)) {
boundedVars.add(triple.object.value);
}
}
} else if ('patterns' in pattern) {
for (const pat of pattern.patterns) {
findBoundVarsFromGroupGraphPattern(pat, boundedVars);
}
}
}
Expand Down Expand Up @@ -111,6 +109,8 @@ export const groupGraphPatternSub: RuleDef<'groupGraphPatternSub', Pattern[]> =

// Check note 13 of the spec.
// TODO: currently optimized for case bind is present.
// Since every iteration, even when no bind is present, we walk the tree collecting variables.
// optimize either by: checking whether bind is present, or by keeping track of variables and passing them through
ACTION(() => {
const boundedVars = new Set<string>();
for (const pattern of patterns) {
Expand All @@ -119,7 +119,7 @@ export const groupGraphPatternSub: RuleDef<'groupGraphPatternSub', Pattern[]> =
if (boundedVars.has(pattern.variable.value)) {
throw new Error(`Variable used to bind is already bound (?${pattern.variable.value})`);
}
} else {
} else if (pattern.type === 'group' || pattern.type === 'bgp') {
findBoundVarsFromGroupGraphPattern(pattern, boundedVars);
}
}
Expand Down
4 changes: 0 additions & 4 deletions src/grammar/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,6 @@ export function unCapitalize<T extends string>(str: T): Uncapitalize<T> {
* Resolves an IRI against a base path
*/
export function resolveIRI(iri: string, base: string | undefined): string {
// Strip off possible angular brackets
if (iri.startsWith('<')) {
iri = iri.slice(1, -1);
}
// Return absolute IRIs unmodified
if (/^[a-z][\d+.a-z-]*:/iu.test(iri)) {
return iri;
Expand Down
4 changes: 2 additions & 2 deletions test/query.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ describe('a SPARQL parser', () => {
): void {
const statics = fs.readdirSync(dir);
for (const file of statics) {
if (file.endsWith('_unary.sparql')) {
if (file.endsWith('_bind-fail.sparql')) {
describe(`test file ${file}`, async() => {
const query = await fsp.readFile(`${dir}/${file}`, 'utf-8');
const result = await fsp.readFile(`${dir}/${file.replace('.sparql', '.json')}`, 'utf-8');
Expand Down Expand Up @@ -60,7 +60,7 @@ describe('a SPARQL parser', () => {

describe('confirms to SPARQL tests', () => {
testPositiveQueriesInDir('./test/statics/sparql', [
[ 'SPARQL 1.1 parser', new Sparql11Parser({ prefixes: { ex: 'http://example.org/' }}) ],
[ 'SPARQL 1.1 parser', new Sparql11Parser({ baseIRI: 'http://example.org/', prefixes: { ex: 'http://example.org/' }}) ],
// [ 'SPARQL 1.2 parser', new Sparql12Parser({ prefixes: { ex: 'http://example.org/' }}) ],
]);
});
Expand Down
31 changes: 31 additions & 0 deletions test/statics/sparql/_bind-fail.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"queryType": "SELECT",
"variables": [
{
"termType": "Wildcard"
}
],
"where": [
{
"type": "bgp",
"triples": [
{
"subject": {
"termType": "Variable",
"value": "s"
},
"predicate": {
"termType": "Variable",
"value": "p"
},
"object": {
"termType": "Variable",
"value": "o"
}
}
]
}
],
"type": "query",
"prefixes": {}
}
9 changes: 9 additions & 0 deletions test/statics/sparql/_bind-fail.sparql
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
SELECT *
{
{
{ :s :p ?Y }
UNION
{ :s :p ?Z }
}
BIND (1 AS ?Y)
}
3 changes: 2 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
},
"include": [
"src/**/*.ts",
"test/**/*.ts"
"test/**/*.ts",
"spec/**/*.ts"
],
"exclude": [
"node_modules"
Expand Down
Loading

0 comments on commit c52eebd

Please sign in to comment.