Skip to content

Commit

Permalink
feat: localMethod suggestion
Browse files Browse the repository at this point in the history
  • Loading branch information
smelukov committed Aug 25, 2023
1 parent 2d912d0 commit 2f7bc0f
Show file tree
Hide file tree
Showing 7 changed files with 427 additions and 212 deletions.
24 changes: 18 additions & 6 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import walk from './lang/walk.js';
import stringify from './lang/stringify.js';
import compile from './lang/compile.js';
import buildin from './lang/compile-buildin.js';
import methods from './methods.js';
import methods, {methodsInfo, makeMethodInfoFacade, createMethodInfoArg, createMethodInfo} from './methods.js';
import assertions from './assertions.js';
import createStatApi from './stat.js';

Expand Down Expand Up @@ -90,10 +90,12 @@ function createQuery(source, options) {
const statMode = Boolean(options.stat);
const tolerantMode = Boolean(options.tolerant);
const localMethods = options.methods ? { ...methods, ...options.methods } : methods;
const localAssetions = options.assertions ? { ...assertions, ...options.assertions } : assertions;
const localAssertions = options.assertions ? { ...assertions, ...options.assertions } : assertions;
const cache = statMode
? (tolerantMode ? cacheTollerantStat : cacheStrictStat)
: (tolerantMode ? cacheTollerant : cacheStrict);
const methodInfoFacade = makeMethodInfoFacade(methodsInfo, options?.methodsInfo);

let fn;

source = String(source);
Expand All @@ -105,20 +107,24 @@ function createQuery(source, options) {
cache.set(source, fn);
}

fn = fn(buildin, localMethods, localAssetions);
fn = fn(buildin, localMethods, localAssertions);

return statMode
? Object.assign((data, context) => createStatApi(source, fn(data, context)), { query: fn })
? Object.assign((data, context) => createStatApi(source, fn(data, context), {
localMethods: {...methods, ...options.methods},
getMethodInfo: methodInfoFacade.get
}), {query: fn, setMethodInfo: methodInfoFacade.set})
: fn;
}

function setup(customMethods, customAssertions) {
function setup(customMethods, customAssertions, {methodsInfo} = {}) {
const cacheStrict = new Map();
const cacheStrictStat = new Map();
const cacheTollerant = new Map();
const cacheTollerantStat = new Map();
const localMethods = { ...methods };
const localAssetions = { ...assertions };
const methodInfoFacade = makeMethodInfoFacade(methodsInfo);

for (const [name, fn] of Object.entries(customMethods || {})) {
if (typeof fn === 'string') {
Expand Down Expand Up @@ -169,7 +175,10 @@ function setup(customMethods, customAssertions) {
} else {
const perform = compileFunction(source, statMode, tolerantMode, options.debug)(buildin, localMethods, localAssetions);
fn = statMode
? Object.assign((data, context) => createStatApi(source, perform(data, context)), { query: perform })
? Object.assign((data, context) => createStatApi(source, perform(data, context), {
localMethods: {...methods, ...customMethods},
getMethodInfo: methodInfoFacade.get
}), {query: perform, setMethodInfo: methodInfoFacade.set})
: perform;
cache.set(source, fn);
}
Expand All @@ -182,6 +191,9 @@ export default Object.assign(createQuery, {
version,
buildin,
methods,
methodsInfo,
createMethodInfo,
createMethodInfoArg,
assertions,
setup,
syntax: {
Expand Down
4 changes: 4 additions & 0 deletions src/lang/compile.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ export default function compile(ast, tolerant = false, suggestions = null) {

normalizedSuggestRanges.push(range);

if (type === 'path') {
normalizedSuggestRanges.push([start, end, JSON.stringify('localMethods')]);
}

return spName;
}

Expand Down
37 changes: 37 additions & 0 deletions src/methods.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,43 @@ function stableSort(array, cmp) {
.map(item => item.value);
}

export function createMethodInfo(args = [], returns = 'any', options = {}) {
return {
args,
returns,
description: options.description ?? ''
};
}

export function createMethodInfoArg(name, type = 'any', options = {}) {
return {
name,
type,
description: options.description ?? '',
options: {
isOptional: options.isOptional || options.defaultValue !== undefined,
defaultValue: options.defaultValue
}
};
}

export function makeMethodInfoFacade(...methodsInfoList) {
const map = new Map(Object.entries(methodsInfoList.reduce((all, item) => Object.assign(all, item), {})));

function set(name, info) {
map.set(name, info);
}

function get(name) {
return map.get(name) ?? null;
}

return {map, set, get, create: createMethodInfo, createArg: createMethodInfoArg};
}

export const methodsInfo = Object.freeze({
bool: createMethodInfo([createMethodInfoArg('arg')], 'bool')
});

export default Object.freeze({
bool: buildin.bool,
Expand Down
15 changes: 11 additions & 4 deletions src/stat.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ const contextToType = {
'in-value': 'value',
'value-subset': 'value',
'var': 'variable',
'assertion': 'assertion'
'assertion': 'assertion',
'localMethods': 'method'
};

function addObjectKeysToSet(object, set) {
Expand Down Expand Up @@ -112,7 +113,7 @@ function findSourcePosRanges(source, pos, points, includeEmpty = false) {
const ranges = [];

for (let [from, to, context, values, related = null] of points) {
if (pos >= from && pos <= to && (includeEmpty || values.size || values.length)) {
if (pos >= from && pos <= to && (includeEmpty || values?.size || values?.length)) {
let text = source.substring(from, to);

if (!/\S/.test(text)) {
Expand Down Expand Up @@ -174,7 +175,7 @@ function defaultFilterFactory(pattern) {
return value => (typeof value === 'string' ? value : String(value)).toLowerCase().indexOf(pattern) !== -1;
}

export default (source, { value, stats, assertions }) => ({
export default (source, { value, stats, assertions }, {localMethods, getMethodInfo}) => ({
get value() {
return value;
},
Expand Down Expand Up @@ -231,6 +232,11 @@ export default (source, { value, stats, assertions }) => ({
}
}
break;
case 'localMethods':
for (const method of Object.keys(localMethods)) {
suggestions.add(method);
}
break;

default:
valuesToSuggestions(context, values, related, suggestions);
Expand Down Expand Up @@ -275,5 +281,6 @@ export default (source, { value, stats, assertions }) => ({
}

return result.length ? result : null;
}
},
getMethodInfo: getMethodInfo
});
32 changes: 32 additions & 0 deletions test/misc.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,35 @@ describe('query/misc', () => {
});
}
});

describe('method info helpers', () => {
it('createMethodInfo', () => {
assert.deepEqual(query.createMethodInfo([], 'some return type', {description: 'some description'}), {
args: [],
description: 'some description',
returns: 'some return type'
});
});

it('createMethodInfoArg', () => {
assert.deepEqual(query.createMethodInfoArg('arg1', 'some arg type', {description: 'some description'}), {
name: 'arg1',
description: 'some description',
options: {
defaultValue: undefined,
isOptional: false
},
type: 'some arg type'
});

assert.deepEqual(query.createMethodInfoArg('arg1', 'some arg type', {description: 'some description', defaultValue: '123'}), {
name: 'arg1',
description: 'some description',
options: {
defaultValue: '123',
isOptional: true
},
type: 'some arg type'
});
});
});

0 comments on commit 2f7bc0f

Please sign in to comment.