eyeling 1.28.8 → 1.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.d.ts CHANGED
@@ -151,6 +151,14 @@ declare module 'eyeling' {
151
151
  document?: EyelingAstBundle;
152
152
  }
153
153
 
154
+ export interface StoreOptions {
155
+ name?: string;
156
+ clear?: boolean;
157
+ path?: string;
158
+ type?: 'memory' | 'persistent';
159
+ backend?: 'memory' | 'level' | 'indexeddb';
160
+ }
161
+
154
162
  export interface ReasonOptions {
155
163
  proof?: boolean;
156
164
  proofComments?: boolean;
@@ -158,6 +166,9 @@ declare module 'eyeling' {
158
166
  args?: string[];
159
167
  maxBuffer?: number;
160
168
  builtinModules?: string | string[];
169
+ store?: string | StoreOptions;
170
+ storePath?: string;
171
+ storeClear?: boolean;
161
172
  }
162
173
 
163
174
  export interface BuiltinRegistrationContext {
@@ -183,6 +194,9 @@ declare module 'eyeling' {
183
194
  dataFactory?: RdfJsDataFactory | null;
184
195
  skipUnsupportedRdfJs?: boolean;
185
196
  builtinModules?: string | string[];
197
+ store?: string | StoreOptions;
198
+ storePath?: string;
199
+ storeClear?: boolean;
186
200
  onDerived?: (item: { triple: string; quad?: RdfJsQuad; quads?: RdfJsQuad[]; df: any }) => void;
187
201
  }
188
202
 
@@ -198,10 +212,45 @@ declare module 'eyeling' {
198
212
  queryQuads?: RdfJsQuad[];
199
213
  }
200
214
 
215
+ export interface FactStore {
216
+ add(triple: EyelingTriple, kind?: 'explicit' | 'inferred'): Promise<boolean>;
217
+ has(triple: EyelingTriple): Promise<boolean>;
218
+ kindOf?(triple: EyelingTriple): Promise<number>;
219
+ match(s?: EyelingTerm | null, p?: EyelingTerm | null, o?: EyelingTerm | null): AsyncIterable<EyelingTriple>;
220
+ batchAdd?(triples: Iterable<EyelingTriple>, kind?: 'explicit' | 'inferred'): Promise<number>;
221
+ clear?(): Promise<void>;
222
+ close?(): Promise<void>;
223
+ }
224
+
225
+ export class MemoryFactStore implements FactStore {
226
+ constructor();
227
+ add(triple: EyelingTriple, kind?: 'explicit' | 'inferred'): Promise<boolean>;
228
+ has(triple: EyelingTriple): Promise<boolean>;
229
+ kindOf(triple: EyelingTriple): Promise<number>;
230
+ match(s?: EyelingTerm | null, p?: EyelingTerm | null, o?: EyelingTerm | null): AsyncIterable<EyelingTriple>;
231
+ batchAdd(triples: Iterable<EyelingTriple>, kind?: 'explicit' | 'inferred'): Promise<number>;
232
+ clear(): Promise<void>;
233
+ close(): Promise<void>;
234
+ }
235
+
236
+ export class PersistentFactStore implements FactStore {
237
+ add(triple: EyelingTriple, kind?: 'explicit' | 'inferred'): Promise<boolean>;
238
+ has(triple: EyelingTriple): Promise<boolean>;
239
+ kindOf(triple: EyelingTriple): Promise<number>;
240
+ match(s?: EyelingTerm | null, p?: EyelingTerm | null, o?: EyelingTerm | null): AsyncIterable<EyelingTriple>;
241
+ batchAdd(triples: Iterable<EyelingTriple>, kind?: 'explicit' | 'inferred'): Promise<number>;
242
+ clear(): Promise<void>;
243
+ close(): Promise<void>;
244
+ }
245
+
201
246
  export function reason(
202
247
  opts: ReasonOptions,
203
248
  input: string | RdfJsReasonInput | EyelingAstBundle | N3SourceListInput,
204
249
  ): string;
250
+ export function runAsync(
251
+ input: string | RdfJsReasonInput | EyelingAstBundle | N3SourceListInput,
252
+ opts?: ReasonStreamOptions,
253
+ ): Promise<ReasonStreamResult & { store?: FactStore }>;
205
254
  export function reasonStream(
206
255
  input: string | RdfJsReasonInput | EyelingAstBundle | N3SourceListInput,
207
256
  opts?: ReasonStreamOptions,
@@ -213,6 +262,7 @@ declare module 'eyeling' {
213
262
 
214
263
  export const INFERENCE_FUSE_EXIT_CODE: 65;
215
264
  export const rdfjs: RdfJsDataFactory;
265
+ export function createFactStore(options?: string | StoreOptions | null): Promise<FactStore>;
216
266
  export function registerBuiltin(iri: string, handler: BuiltinHandler): BuiltinHandler;
217
267
  export function unregisterBuiltin(iri: string): boolean;
218
268
  export function registerBuiltinModule(mod: any, origin?: string): boolean;
@@ -230,7 +280,13 @@ declare module 'eyeling/browser' {
230
280
  export type ReasonStreamOptions = import('eyeling').ReasonStreamOptions;
231
281
  export type ReasonStreamResult = import('eyeling').ReasonStreamResult;
232
282
  export type BuiltinHandler = import('eyeling').BuiltinHandler;
283
+ export type StoreOptions = import('eyeling').StoreOptions;
284
+ export type FactStore = import('eyeling').FactStore;
233
285
 
286
+ export function runAsync(
287
+ input: string | RdfJsReasonInput | EyelingAstBundle | N3SourceListInput,
288
+ opts?: ReasonStreamOptions,
289
+ ): Promise<ReasonStreamResult & { store?: FactStore }>;
234
290
  export function reasonStream(
235
291
  input: string | RdfJsReasonInput | EyelingAstBundle | N3SourceListInput,
236
292
  opts?: ReasonStreamOptions,
@@ -242,6 +298,7 @@ declare module 'eyeling/browser' {
242
298
 
243
299
  export const INFERENCE_FUSE_EXIT_CODE: 65;
244
300
  export const rdfjs: RdfJsDataFactory;
301
+ export function createFactStore(options?: string | StoreOptions | null): Promise<FactStore>;
245
302
  export function registerBuiltin(iri: string, handler: BuiltinHandler): BuiltinHandler;
246
303
  export function unregisterBuiltin(iri: string): boolean;
247
304
  export function registerBuiltinModule(mod: any, origin?: string): boolean;
@@ -249,10 +306,12 @@ declare module 'eyeling/browser' {
249
306
 
250
307
  const eyeling: {
251
308
  readonly version: string;
309
+ runAsync: typeof runAsync;
252
310
  reasonStream: typeof reasonStream;
253
311
  reasonRdfJs: typeof reasonRdfJs;
254
312
  readonly INFERENCE_FUSE_EXIT_CODE: typeof INFERENCE_FUSE_EXIT_CODE;
255
313
  rdfjs: typeof rdfjs;
314
+ createFactStore: typeof createFactStore;
256
315
  registerBuiltin: typeof registerBuiltin;
257
316
  unregisterBuiltin: typeof unregisterBuiltin;
258
317
  registerBuiltinModule: typeof registerBuiltinModule;
package/index.js CHANGED
@@ -42,6 +42,15 @@ function reason(opt = {}, input = '') {
42
42
 
43
43
  if (opt.rdf) args.push('--rdf');
44
44
 
45
+ if (typeof opt.store === 'string' && opt.store) args.push('--store', opt.store);
46
+ else if (opt.store && typeof opt.store === 'object') {
47
+ if (opt.store.name) args.push('--store', String(opt.store.name));
48
+ if (opt.store.clear) args.push('--store-clear');
49
+ if (opt.store.path) args.push('--store-path', String(opt.store.path));
50
+ }
51
+ if (opt.storePath) args.push('--store-path', String(opt.storePath));
52
+ if (opt.storeClear) args.push('--store-clear');
53
+
45
54
  if (Array.isArray(opt.args)) args.push(...opt.args);
46
55
 
47
56
  const builtinModules = Array.isArray(opt.builtinModules)
@@ -106,8 +115,13 @@ function reason(opt = {}, input = '') {
106
115
  }
107
116
  }
108
117
 
118
+ async function runAsync(input = '', opt = {}) {
119
+ return engine.runAsync(input, opt || {});
120
+ }
121
+
109
122
  module.exports = {
110
123
  reason,
124
+ runAsync,
111
125
  reasonStream: bundleApi.reasonStream,
112
126
  reasonRdfJs: bundleApi.reasonRdfJs,
113
127
  rdfjs: dataFactory,
@@ -116,6 +130,9 @@ module.exports = {
116
130
  registerBuiltinModule: engine.registerBuiltinModule,
117
131
  loadBuiltinModule: engine.loadBuiltinModule,
118
132
  listBuiltinIris: engine.listBuiltinIris,
133
+ createFactStore: engine.createFactStore,
134
+ MemoryFactStore: engine.MemoryFactStore,
135
+ PersistentFactStore: engine.PersistentFactStore,
119
136
  };
120
137
 
121
138
  // small interop nicety for ESM default import
package/lib/cli.js CHANGED
@@ -710,6 +710,9 @@ async function main() {
710
710
  ` -p, --proof Enable proof explanations.\n` +
711
711
  ` -r, --rdf Enable RDF/TriG input/output compatibility.\n` +
712
712
  ` --stream-messages Process RDF Message Logs one message at a time under -r.\n` +
713
+ ` --store <name> Use an optional persistent fact store.\n` +
714
+ ` --store-clear Clear the named store before this run.\n` +
715
+ ` --store-path <dir> Node.js persistent store directory.\n` +
713
716
  ` -s, --super-restricted Disable all builtins except => and <=.\n` +
714
717
  ` -t, --stream Stream derived triples as soon as they are derived.\n` +
715
718
  ` -v, --version Print version and exit.\n`;
@@ -746,6 +749,35 @@ async function main() {
746
749
  builtinModules.push(a.slice('--builtin='.length));
747
750
  continue;
748
751
  }
752
+ if (a === '--store') {
753
+ const next = argv[i + 1];
754
+ if (!next || next.startsWith('-')) {
755
+ console.error('Error: --store expects a store name.');
756
+ process.exit(1);
757
+ }
758
+ argv.__storeName = next;
759
+ i += 1;
760
+ continue;
761
+ }
762
+ if (typeof a === 'string' && a.startsWith('--store=')) {
763
+ argv.__storeName = a.slice('--store='.length);
764
+ continue;
765
+ }
766
+ if (a === '--store-path') {
767
+ const next = argv[i + 1];
768
+ if (!next || next.startsWith('-')) {
769
+ console.error('Error: --store-path expects a directory path.');
770
+ process.exit(1);
771
+ }
772
+ argv.__storePath = next;
773
+ i += 1;
774
+ continue;
775
+ }
776
+ if (typeof a === 'string' && a.startsWith('--store-path=')) {
777
+ argv.__storePath = a.slice('--store-path='.length);
778
+ continue;
779
+ }
780
+ if (a === '--store-clear') continue;
749
781
  if (a === '-' || !a.startsWith('-')) positional.push(a);
750
782
  }
751
783
 
@@ -753,6 +785,9 @@ async function main() {
753
785
  const streamMode = argv.includes('--stream') || argv.includes('-t');
754
786
  const streamMessagesMode = argv.includes('--stream-messages');
755
787
  const rdfMode = argv.includes('--rdf') || argv.includes('-r');
788
+ const storeName = argv.__storeName || null;
789
+ const storePath = argv.__storePath || null;
790
+ const storeClear = argv.includes('--store-clear');
756
791
 
757
792
  // --enforce-https: rewrite http:// -> https:// for log dereferencing builtins
758
793
  if (argv.includes('--enforce-https') || argv.includes('-e')) {
@@ -776,6 +811,10 @@ async function main() {
776
811
 
777
812
 
778
813
  if (streamMessagesMode) {
814
+ if (storeName) {
815
+ console.error('Error: --store cannot be combined with --stream-messages yet.');
816
+ process.exit(1);
817
+ }
779
818
  if (!rdfMode) {
780
819
  console.error('Error: --stream-messages requires -r/--rdf.');
781
820
  process.exit(1);
@@ -931,6 +970,69 @@ function factsContainOutputStrings(triplesForOutput) {
931
970
  const hasQueries = Array.isArray(qrules) && qrules.length;
932
971
  const mayAutoRenderOutputStrings = programMayProduceOutputStrings(triples, frules, qrules);
933
972
 
973
+ if (storeName) {
974
+ if (streamMode) {
975
+ console.error('Error: --store cannot be combined with --stream yet.');
976
+ process.exit(1);
977
+ }
978
+
979
+ const storeResult = await engine.runAsync(
980
+ { prefixes, triples, frules, brules, logQueryRules: qrules },
981
+ {
982
+ proof: engine.getProofCommentsEnabled(),
983
+ rdf: rdfMode,
984
+ store: { name: storeName, clear: storeClear, path: storePath || undefined },
985
+ },
986
+ );
987
+
988
+ const storeFacts = storeResult.facts || [];
989
+ const storeDerived = storeResult.derived || [];
990
+ const storeHasQueries = !!storeResult.queryMode;
991
+ const storeOutTriples = storeHasQueries ? (storeResult.queryTriples || []) : (mayAutoRenderOutputStrings && !engine.getProofCommentsEnabled() ? [] : storeDerived.map((df) => df.fact));
992
+ const storeOutDerived = storeHasQueries ? (storeResult.queryDerived || []) : storeDerived;
993
+ const renderedOutputTriples = storeHasQueries ? storeOutTriples : storeFacts;
994
+
995
+ if (factsContainOutputStrings(renderedOutputTriples)) {
996
+ process.stdout.write(engine.collectOutputStringsFromFacts(renderedOutputTriples, prefixes));
997
+ if (storeResult.store && typeof storeResult.store.close === 'function') await storeResult.store.close();
998
+ return;
999
+ }
1000
+
1001
+ if (engine.getProofCommentsEnabled()) {
1002
+ process.stdout.write(engine.renderProofDocument(storeOutDerived, storeDerived.concat(storeOutDerived || []), triples, prefixes, brules));
1003
+ if (storeResult.store && typeof storeResult.store.close === 'function') await storeResult.store.close();
1004
+ return;
1005
+ }
1006
+
1007
+ let bodyText = '';
1008
+ if (rdfMode) bodyText = storeOutTriples.map((tr) => engine.tripleToRdfCompatible(tr, prefixes)).join('\n');
1009
+ else if (storeHasQueries) bodyText = engine.prettyPrintQueryTriples(storeOutTriples, prefixes);
1010
+
1011
+ let usedPrefixes = prefixes.prefixesUsedForOutput(storeOutTriples);
1012
+ if (rdfMode && bodyText) usedPrefixes = usedPrefixes.filter(([pfx]) => pfx === '' || bodyText.includes(pfx + ':'));
1013
+
1014
+ if (rdfMode && bodyText.includes('<<(')) {
1015
+ console.log('VERSION "1.2"');
1016
+ console.log();
1017
+ }
1018
+
1019
+ for (const [pfx, base] of usedPrefixes) {
1020
+ if (pfx === '') console.log(`@prefix : <${base}> .`);
1021
+ else console.log(`@prefix ${pfx}: <${base}> .`);
1022
+ }
1023
+ if (storeOutTriples.length && usedPrefixes.length) console.log();
1024
+
1025
+ if (bodyText) process.stdout.write(String(bodyText).replace(/\s*$/g, '') + '\n');
1026
+ else {
1027
+ for (const df of storeOutDerived) {
1028
+ console.log(rdfMode ? engine.tripleToRdfCompatible(df.fact, prefixes) : engine.tripleToN3(df.fact, prefixes));
1029
+ }
1030
+ }
1031
+
1032
+ if (storeResult.store && typeof storeResult.store.close === 'function') await storeResult.store.close();
1033
+ return;
1034
+ }
1035
+
934
1036
  if (streamMode && !hasQueries && !mayAutoRenderOutputStrings && !engine.getProofCommentsEnabled()) {
935
1037
  const usedInInput = mergedDocument.usedPrefixes instanceof Set ? new Set(mergedDocument.usedPrefixes) : new Set();
936
1038
  const outPrefixes = restrictPrefixEnv(prefixes, usedInInput);
package/lib/engine.js CHANGED
@@ -97,6 +97,7 @@ const {
97
97
  getDataFactory,
98
98
  internalTripleToRdfJsQuads,
99
99
  normalizeParsedReasonerInputSync,
100
+ normalizeParsedReasonerInputAsync,
100
101
  normalizeReasonerInputSync,
101
102
  normalizeReasonerInputAsync,
102
103
  } = require('./rdfjs');
@@ -105,6 +106,7 @@ const trace = require('./trace');
105
106
  const { deterministicSkolemIdFromKey } = require('./skolem');
106
107
 
107
108
  const deref = require('./deref');
109
+ const { createFactStore, collectStore, MemoryFactStore, PersistentFactStore } = require('./store');
108
110
 
109
111
  const hasOwn = Object.prototype.hasOwnProperty;
110
112
 
@@ -3783,6 +3785,120 @@ function reasonStream(input, opts = {}) {
3783
3785
  return __out;
3784
3786
  }
3785
3787
 
3788
+
3789
+ async function __parseRunAsyncInput(input, opts) {
3790
+ const {
3791
+ baseIri = null,
3792
+ proof = false,
3793
+ rdf = false,
3794
+ sourceLabel = '<input>',
3795
+ } = opts || {};
3796
+
3797
+ const parsedSourceList = parseN3SourceList(input, { baseIri, rdf: !!rdf, sourceLocations: !!proof });
3798
+ if (parsedSourceList) return parsedSourceList;
3799
+
3800
+ const parsedObject = await normalizeParsedReasonerInputAsync(input);
3801
+ if (parsedObject) {
3802
+ if (baseIri && parsedObject.prefixes && typeof parsedObject.prefixes.setBase === 'function') parsedObject.prefixes.setBase(baseIri);
3803
+ return parsedObject;
3804
+ }
3805
+
3806
+ const n3Text = await normalizeReasonerInputAsync(input);
3807
+ return parseN3Text(n3Text, {
3808
+ baseIri: baseIri || '',
3809
+ label: sourceLabel || '<input>',
3810
+ keepSourceArtifacts: false,
3811
+ sourceLocations: !!proof,
3812
+ rdf: !!rdf,
3813
+ });
3814
+ }
3815
+
3816
+ function __withoutStoreOptions(opts) {
3817
+ const out = { ...(opts || {}) };
3818
+ delete out.store;
3819
+ delete out.storePath;
3820
+ delete out.storeClear;
3821
+ return out;
3822
+ }
3823
+
3824
+ function __normalizeStoreOption(opts) {
3825
+ const cfg = opts && opts.store;
3826
+ if (!cfg) return null;
3827
+ if (typeof cfg === 'string') return { name: cfg, path: opts.storePath || undefined, clear: !!opts.storeClear };
3828
+ if (typeof cfg === 'object') {
3829
+ return {
3830
+ ...cfg,
3831
+ path: cfg.path || opts.storePath || undefined,
3832
+ clear: !!(cfg.clear || opts.storeClear),
3833
+ };
3834
+ }
3835
+ throw new TypeError('runAsync option "store" must be a store name string or a store options object');
3836
+ }
3837
+
3838
+ async function runAsync(input, opts = {}) {
3839
+ const storeConfig = __normalizeStoreOption(opts);
3840
+ const runOpts = __withoutStoreOptions(opts);
3841
+
3842
+ // No store configured: keep ordinary in-memory behavior, but accept async RDF/JS
3843
+ // iterables by normalizing the input before calling the synchronous engine.
3844
+ if (!storeConfig) {
3845
+ const normalizedInput = parseN3SourceList(input, {
3846
+ baseIri: runOpts.baseIri || null,
3847
+ rdf: !!runOpts.rdf,
3848
+ sourceLocations: !!runOpts.proof,
3849
+ }) || (await normalizeReasonerInputAsync(input));
3850
+ return reasonStream(normalizedInput, runOpts);
3851
+ }
3852
+
3853
+ const store = await createFactStore(storeConfig);
3854
+ let closeStore = true;
3855
+ try {
3856
+ const parsed = await __parseRunAsyncInput(input, runOpts);
3857
+
3858
+ // Persist the newly supplied explicit facts first, then include all stored
3859
+ // facts as the starting closure for this run. This lets --store reuse facts
3860
+ // across runs while keeping the current in-memory prover semantics intact.
3861
+ await store.batchAdd(parsed.triples || [], 'explicit');
3862
+ const storedTriples = await collectStore(store);
3863
+
3864
+ const storedKeys = new Set();
3865
+ for (const tr of storedTriples) storedKeys.add(require('./store').tripleToStoreKey(tr));
3866
+ const mergedTriples = storedTriples.slice();
3867
+ for (const tr of parsed.triples || []) {
3868
+ const key = require('./store').tripleToStoreKey(tr);
3869
+ if (!storedKeys.has(key)) {
3870
+ storedKeys.add(key);
3871
+ mergedTriples.push(tr);
3872
+ }
3873
+ }
3874
+
3875
+ const result = reasonStream(
3876
+ {
3877
+ prefixes: parsed.prefixes,
3878
+ triples: mergedTriples,
3879
+ frules: parsed.frules,
3880
+ brules: parsed.brules,
3881
+ logQueryRules: parsed.logQueryRules,
3882
+ },
3883
+ runOpts,
3884
+ );
3885
+
3886
+ await store.batchAdd((result.derived || []).map((df) => df.fact), 'inferred');
3887
+ result.store = store;
3888
+ closeStore = false;
3889
+ return result;
3890
+ } catch (e) {
3891
+ await store.close();
3892
+ throw e;
3893
+ } finally {
3894
+ // Keep result.store usable for callers. On exceptional paths it is closed
3895
+ // above; on success callers may close it when they are done.
3896
+ if (closeStore) {
3897
+ try { await store.close(); } catch {}
3898
+ }
3899
+ }
3900
+ }
3901
+
3786
3902
  function reasonRdfJs(input, opts = {}) {
3787
3903
  const { dataFactory = null, skipUnsupportedRdfJs = false, ...restOpts } = opts || {};
3788
3904
  const rdfFactory = getDataFactory(dataFactory);
@@ -3890,6 +4006,7 @@ function setTracePrefixes(v) {
3890
4006
 
3891
4007
  module.exports = {
3892
4008
  reasonStream,
4009
+ runAsync,
3893
4010
  reasonRdfJs,
3894
4011
  collectLogQueryConclusions,
3895
4012
  forwardChainAndCollectLogQueryConclusions,
@@ -3926,4 +4043,7 @@ module.exports = {
3926
4043
  loadBuiltinModule,
3927
4044
  listBuiltinIris,
3928
4045
  INFERENCE_FUSE_EXIT_CODE,
4046
+ createFactStore,
4047
+ MemoryFactStore,
4048
+ PersistentFactStore,
3929
4049
  };
package/lib/entry.js CHANGED
@@ -17,6 +17,7 @@ const { dataFactory } = require('./rdfjs');
17
17
  module.exports = {
18
18
  // public
19
19
  reasonStream: engine.reasonStream,
20
+ runAsync: engine.runAsync,
20
21
  reasonRdfJs: engine.reasonRdfJs,
21
22
  rdfjs: dataFactory,
22
23
  main: engine.main,
@@ -41,6 +42,9 @@ module.exports = {
41
42
  registerBuiltinModule: engine.registerBuiltinModule,
42
43
  loadBuiltinModule: engine.loadBuiltinModule,
43
44
  listBuiltinIris: engine.listBuiltinIris,
45
+ createFactStore: engine.createFactStore,
46
+ MemoryFactStore: engine.MemoryFactStore,
47
+ PersistentFactStore: engine.PersistentFactStore,
44
48
  getEnforceHttpsEnabled: engine.getEnforceHttpsEnabled,
45
49
  setEnforceHttpsEnabled: engine.setEnforceHttpsEnabled,
46
50
  getProofCommentsEnabled: engine.getProofCommentsEnabled,
package/lib/lexer.js CHANGED
@@ -1547,7 +1547,76 @@ function lex(inputText, opts = {}) {
1547
1547
  continue;
1548
1548
  }
1549
1549
 
1550
- // 5) Single-character punctuation. Use a switch rather than allocating a
1550
+ // 5) Numeric literal (integer, decimal, or double). Turtle/N3 numeric
1551
+ // literals may have a leading sign and decimals may start with '.', e.g.
1552
+ // '+42' and '.5'. Reject repeated decimal points so '1.2.3'
1553
+ // cannot be misread as one impossible numeric-like token.
1554
+ if (
1555
+ isAsciiDigit(c) ||
1556
+ ((c === '+' || c === '-') && (isAsciiDigit(peek(1)) || (peek(1) === '.' && isAsciiDigit(peek(2))))) ||
1557
+ (c === '.' && isAsciiDigit(peek(1)) && !isAsciiDigit(peek(-1)))
1558
+ ) {
1559
+ const start = i;
1560
+ const numChars = [];
1561
+
1562
+ if (chars[i] === '+' || chars[i] === '-') {
1563
+ numChars.push(chars[i]);
1564
+ i++;
1565
+ }
1566
+
1567
+ if (chars[i] === '.') {
1568
+ numChars.push('.');
1569
+ i++;
1570
+ while (i < n && isAsciiDigit(chars[i])) {
1571
+ numChars.push(chars[i]);
1572
+ i++;
1573
+ }
1574
+ } else {
1575
+ while (i < n && isAsciiDigit(chars[i])) {
1576
+ numChars.push(chars[i]);
1577
+ i++;
1578
+ }
1579
+ if (i < n && chars[i] === '.' && i + 1 < n && isAsciiDigit(chars[i + 1])) {
1580
+ numChars.push('.');
1581
+ i++;
1582
+ while (i < n && isAsciiDigit(chars[i])) {
1583
+ numChars.push(chars[i]);
1584
+ i++;
1585
+ }
1586
+ }
1587
+ }
1588
+
1589
+ if (i < n && chars[i] === '.' && i + 1 < n && isAsciiDigit(chars[i + 1])) {
1590
+ throw new N3SyntaxError('Malformed numeric literal: multiple decimal points', start);
1591
+ }
1592
+
1593
+ // Optional exponent part: e.g., 1e0, 1.1e-3, .5E+0.
1594
+ if (i < n && (chars[i] === 'e' || chars[i] === 'E')) {
1595
+ let j = i + 1;
1596
+ if (j < n && (chars[j] === '+' || chars[j] === '-')) j++;
1597
+ if (j < n && isAsciiDigit(chars[j])) {
1598
+ numChars.push(chars[i]); // e/E
1599
+ i++;
1600
+ if (i < n && (chars[i] === '+' || chars[i] === '-')) {
1601
+ numChars.push(chars[i]);
1602
+ i++;
1603
+ }
1604
+ while (i < n && isAsciiDigit(chars[i])) {
1605
+ numChars.push(chars[i]);
1606
+ i++;
1607
+ }
1608
+ }
1609
+ }
1610
+
1611
+ if (i < n && chars[i] === '.' && i + 1 < n && isAsciiDigit(chars[i + 1])) {
1612
+ throw new N3SyntaxError('Malformed numeric literal: multiple decimal points', start);
1613
+ }
1614
+
1615
+ tokens.push(new Token('Literal', numChars.join(''), start));
1616
+ continue;
1617
+ }
1618
+
1619
+ // 6) Single-character punctuation. Use a switch rather than allocating a
1551
1620
  // mapping object for every punctuation token in large inputs.
1552
1621
  switch (c) {
1553
1622
  case '{':
@@ -1668,13 +1737,17 @@ function lex(inputText, opts = {}) {
1668
1737
  }
1669
1738
  continue;
1670
1739
  }
1740
+ if (cc === '\n' || cc === '\r') {
1741
+ throw new N3SyntaxError('Unescaped newline in short string literal', start);
1742
+ }
1671
1743
  if (cc === '"') {
1672
1744
  closed = true;
1673
1745
  break;
1674
1746
  }
1675
1747
  if (sChars !== null) sChars.push(cc);
1676
1748
  }
1677
- const rawContent = sChars === null ? sliceChars(contentStart, closed ? i - 1 : i) : sChars.join('');
1749
+ if (!closed) throw new N3SyntaxError('Unterminated short string literal "..."', start);
1750
+ const rawContent = sChars === null ? sliceChars(contentStart, i - 1) : sChars.join('');
1678
1751
  const decoded = sChars === null ? rawContent : decodeN3StringEscapes(rawContent, start);
1679
1752
  if (sChars !== null || inputMayContainInvalidStringChar) assertValidStringLiteralValue(decoded, start);
1680
1753
  const s = JSON.stringify(decoded); // canonical short quoted form
@@ -1758,13 +1831,17 @@ function lex(inputText, opts = {}) {
1758
1831
  }
1759
1832
  continue;
1760
1833
  }
1834
+ if (cc === '\n' || cc === '\r') {
1835
+ throw new N3SyntaxError('Unescaped newline in short string literal', start);
1836
+ }
1761
1837
  if (cc === "'") {
1762
1838
  closed = true;
1763
1839
  break;
1764
1840
  }
1765
1841
  if (sChars !== null) sChars.push(cc);
1766
1842
  }
1767
- const rawContent = sChars === null ? sliceChars(contentStart, closed ? i - 1 : i) : sChars.join('');
1843
+ if (!closed) throw new N3SyntaxError("Unterminated short string literal '...'", start);
1844
+ const rawContent = sChars === null ? sliceChars(contentStart, i - 1) : sChars.join('');
1768
1845
  const decoded = sChars === null ? rawContent : decodeN3StringEscapes(rawContent, start);
1769
1846
  if (sChars !== null || inputMayContainInvalidStringChar) assertValidStringLiteralValue(decoded, start);
1770
1847
  const s = JSON.stringify(decoded); // canonical short quoted form
@@ -1847,52 +1924,6 @@ function lex(inputText, opts = {}) {
1847
1924
  continue;
1848
1925
  }
1849
1926
 
1850
- // 6) Numeric literal (integer or float)
1851
- if (isAsciiDigit(c) || (c === '-' && peek(1) !== null && isAsciiDigit(peek(1)))) {
1852
- const start = i;
1853
- const numChars = [c];
1854
- i++;
1855
- while (i < n) {
1856
- const cc = chars[i];
1857
- if (isAsciiDigit(cc)) {
1858
- numChars.push(cc);
1859
- i++;
1860
- continue;
1861
- }
1862
- if (cc === '.') {
1863
- if (i + 1 < n && isAsciiDigit(chars[i + 1])) {
1864
- numChars.push('.');
1865
- i++;
1866
- continue;
1867
- } else {
1868
- break;
1869
- }
1870
- }
1871
- break;
1872
- }
1873
-
1874
- // Optional exponent part: e.g., 1e0, 1.1e-3, 1.1E+0
1875
- if (i < n && (chars[i] === 'e' || chars[i] === 'E')) {
1876
- let j = i + 1;
1877
- if (j < n && (chars[j] === '+' || chars[j] === '-')) j++;
1878
- if (j < n && isAsciiDigit(chars[j])) {
1879
- numChars.push(chars[i]); // e/E
1880
- i++;
1881
- if (i < n && (chars[i] === '+' || chars[i] === '-')) {
1882
- numChars.push(chars[i]);
1883
- i++;
1884
- }
1885
- while (i < n && isAsciiDigit(chars[i])) {
1886
- numChars.push(chars[i]);
1887
- i++;
1888
- }
1889
- }
1890
- }
1891
-
1892
- tokens.push(new Token('Literal', numChars.join(''), start));
1893
- continue;
1894
- }
1895
-
1896
1927
  // 7) Identifiers / keywords / QNames
1897
1928
  const start = i;
1898
1929
  const word = readIdentText(start);
package/lib/rdfjs.js CHANGED
@@ -952,6 +952,7 @@ module.exports = {
952
952
  internalTripleToRdfJsQuads,
953
953
  internalTripleToRdfJsQuadInGraph,
954
954
  normalizeParsedReasonerInputSync,
955
+ normalizeParsedReasonerInputAsync,
955
956
  normalizeReasonerInputSync,
956
957
  normalizeReasonerInputAsync,
957
958
  hasEyelingObjectInput,