@lexjs/web 2.0.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/LICENSE +16 -0
- package/README.md +800 -0
- package/dist/actions/core-actions.js +6 -0
- package/dist/actions/npm-actions.js +38 -0
- package/dist/actions/permission-actions.js +21 -0
- package/dist/api/browser/browser.js +111 -0
- package/dist/api/browser/browser.types.js +1 -0
- package/dist/api/matchers/matchers.js +9 -0
- package/dist/api/site/site.js +248 -0
- package/dist/api/site/site.types.js +1 -0
- package/dist/api/utils/extract-protocol.js +10 -0
- package/dist/api/utils/remove-protocol.js +8 -0
- package/dist/api/utils/return-type-guard.js +7 -0
- package/dist/api/utils/slash.js +21 -0
- package/dist/command/args/config-args.js +9 -0
- package/dist/command/args/data-args.js +110 -0
- package/dist/command/args/invalid-args.js +11 -0
- package/dist/command/args/query-args.js +121 -0
- package/dist/command/args/validate-args.js +126 -0
- package/dist/command/options.js +58 -0
- package/dist/config/config-file.js +66 -0
- package/dist/config/config-flags.js +42 -0
- package/dist/config/file-editor.js +26 -0
- package/dist/config/handle-config.js +12 -0
- package/dist/constants.js +15 -0
- package/dist/create-app/main.js +121 -0
- package/dist/create-app/paths.js +24 -0
- package/dist/create-app/schema/base.json +21 -0
- package/dist/create-app/schema/browsers.json +60 -0
- package/dist/create-app/schema/sites.json +71 -0
- package/dist/create-app/script-contents.js +18 -0
- package/dist/create-app/tree.js +25 -0
- package/dist/data/app-data.js +12 -0
- package/dist/data/config-data.js +35 -0
- package/dist/data/defaults.js +22 -0
- package/dist/data/initial-sites.js +36 -0
- package/dist/data/sort-config-data.js +17 -0
- package/dist/helpers/find-browser.js +9 -0
- package/dist/helpers/find-config-item.js +23 -0
- package/dist/helpers/find-nested.js +24 -0
- package/dist/helpers/find-profile.js +11 -0
- package/dist/helpers/find-site.js +15 -0
- package/dist/helpers/get-browser-name.js +9 -0
- package/dist/helpers/get-query-profiles.js +34 -0
- package/dist/main.js +19 -0
- package/dist/query/get-profiles-config.js +10 -0
- package/dist/query/get-query-browsers.js +33 -0
- package/dist/query/get-query-sites.js +49 -0
- package/dist/query/get-urls.js +85 -0
- package/dist/query/open-urls.js +30 -0
- package/dist/query/print-query.js +24 -0
- package/dist/query/query.js +19 -0
- package/dist/types/arg.types.js +1 -0
- package/dist/types/config.types.js +1 -0
- package/dist/types/primitive.type.js +1 -0
- package/dist/types/query.types.js +1 -0
- package/dist/types/utility.types.js +1 -0
- package/dist/utils/get-package-info.js +10 -0
- package/dist/utils/logger.js +15 -0
- package/dist/utils/parse-data.js +15 -0
- package/dist/utils/transform-text.js +7 -0
- package/dist/utils/yaml-files.js +6 -0
- package/package.json +88 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"title": "Browsers Config",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"properties": {
|
|
6
|
+
"$schema": {
|
|
7
|
+
"type": "string"
|
|
8
|
+
}
|
|
9
|
+
},
|
|
10
|
+
"additionalProperties": {
|
|
11
|
+
"oneOf": [{ "$ref": "#/$defs/Browser" }, { "type": "null" }]
|
|
12
|
+
},
|
|
13
|
+
"$defs": {
|
|
14
|
+
"Browser": {
|
|
15
|
+
"description": "Browser config definition",
|
|
16
|
+
"type": "object",
|
|
17
|
+
"additionalProperties": false,
|
|
18
|
+
"properties": {
|
|
19
|
+
"default": {
|
|
20
|
+
"type": "boolean",
|
|
21
|
+
"description": "If true, this browser is considered a default option."
|
|
22
|
+
},
|
|
23
|
+
"alias": {
|
|
24
|
+
"$ref": "base.json#/$defs/alias",
|
|
25
|
+
"description": "One or more aliases for the browser."
|
|
26
|
+
},
|
|
27
|
+
"appPath": {
|
|
28
|
+
"description": "Path to the browser executable.",
|
|
29
|
+
"type": "string"
|
|
30
|
+
},
|
|
31
|
+
"profiles": {
|
|
32
|
+
"description": "Profile definitions for this browser.",
|
|
33
|
+
"type": "object",
|
|
34
|
+
"additionalProperties": {
|
|
35
|
+
"oneOf": [{ "$ref": "#/$defs/Profile" }, { "type": "string" }]
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"Profile": {
|
|
41
|
+
"description": "Defines a specific user profile for a browser.",
|
|
42
|
+
"type": "object",
|
|
43
|
+
"properties": {
|
|
44
|
+
"directory": {
|
|
45
|
+
"description": "Name of directory where profile data is stored.",
|
|
46
|
+
"type": "string"
|
|
47
|
+
},
|
|
48
|
+
"default": {
|
|
49
|
+
"type": "boolean",
|
|
50
|
+
"description": "If true, this profile is considered a default option."
|
|
51
|
+
},
|
|
52
|
+
"alias": {
|
|
53
|
+
"$ref": "base.json#/$defs/alias",
|
|
54
|
+
"description": "One or more aliases for the profile."
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
"required": ["directory"]
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"title": "Sites Config",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"properties": {
|
|
6
|
+
"$schema": {
|
|
7
|
+
"type": "string"
|
|
8
|
+
}
|
|
9
|
+
},
|
|
10
|
+
"additionalProperties": {
|
|
11
|
+
"$ref": "#/$defs/Site"
|
|
12
|
+
},
|
|
13
|
+
"$defs": {
|
|
14
|
+
"Site": {
|
|
15
|
+
"type": "object",
|
|
16
|
+
"additionalProperties": false,
|
|
17
|
+
"required": ["url"],
|
|
18
|
+
"properties": {
|
|
19
|
+
"url": {
|
|
20
|
+
"description": "Primary URL of the site (e.g. 'google.com')",
|
|
21
|
+
"type": "string",
|
|
22
|
+
"format": "uri"
|
|
23
|
+
},
|
|
24
|
+
"query": {
|
|
25
|
+
"description": "Query path to search the site (e.g., 'search?q=')",
|
|
26
|
+
"oneOf": [{ "$ref": "#/$defs/QueryObject" }, { "type": "string" }]
|
|
27
|
+
},
|
|
28
|
+
"default": {
|
|
29
|
+
"type": "boolean",
|
|
30
|
+
"description": "If true, this site is considered a default option."
|
|
31
|
+
},
|
|
32
|
+
"alias": {
|
|
33
|
+
"$ref": "base.json#/$defs/alias",
|
|
34
|
+
"description": "One or more aliases for the site."
|
|
35
|
+
},
|
|
36
|
+
"delimiter": {
|
|
37
|
+
"description": "A character or string used to separate search terms.",
|
|
38
|
+
"type": "string"
|
|
39
|
+
},
|
|
40
|
+
"resources": {
|
|
41
|
+
"description": "Resource definitions for specific parts of the site. Supports deep, nested structures.",
|
|
42
|
+
"type": "object",
|
|
43
|
+
"additionalProperties": {
|
|
44
|
+
"oneOf": [
|
|
45
|
+
{ "$ref": "base.json#/$defs/NestedStringObject" },
|
|
46
|
+
{ "type": "string" }
|
|
47
|
+
]
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
"QueryObject": {
|
|
53
|
+
"description": "Object describing query path for the site. Supports deep, nested structures.",
|
|
54
|
+
"type": "object",
|
|
55
|
+
"properties": {
|
|
56
|
+
"main": {
|
|
57
|
+
"description": "Main query path for the site.",
|
|
58
|
+
"type": "string"
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
"additionalProperties": {
|
|
62
|
+
"description": "Additional query path for the site.",
|
|
63
|
+
"oneOf": [
|
|
64
|
+
{ "$ref": "base.json#/$defs/NestedStringObject" },
|
|
65
|
+
{ "type": "string" }
|
|
66
|
+
]
|
|
67
|
+
},
|
|
68
|
+
"required": ["main"]
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { paths } from './paths.js';
|
|
2
|
+
export const bashScript = `#!/usr/bin/env bash
|
|
3
|
+
|
|
4
|
+
if test -f "${paths.main}"; then
|
|
5
|
+
node "${paths.main}" "$@"
|
|
6
|
+
fi
|
|
7
|
+
`;
|
|
8
|
+
export const bashStartScript = `#!/usr/bin/env bash
|
|
9
|
+
|
|
10
|
+
if test -d "${paths.bin}"; then
|
|
11
|
+
export PATH=${paths.bin}:$PATH
|
|
12
|
+
fi`;
|
|
13
|
+
export const powershellScript = `#!/usr/bin/env pwsh
|
|
14
|
+
|
|
15
|
+
if (Test-Path -Path "${paths.main}") {
|
|
16
|
+
node "${paths.main}" $args
|
|
17
|
+
}
|
|
18
|
+
`;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { BASE_SCHEMA_FILE, BROWSERS_SCHEMA_FILE, DATA_FILE, PACKAGE_NAME, SITES_SCHEMA_FILE, } from '../constants.js';
|
|
2
|
+
import baseSchema from './schema/base.json' with { type: 'json' };
|
|
3
|
+
import browsersSchema from './schema/browsers.json' with { type: 'json' };
|
|
4
|
+
import sitesSchema from './schema/sites.json' with { type: 'json' };
|
|
5
|
+
export const initialTree = {
|
|
6
|
+
bin: {},
|
|
7
|
+
lib: {},
|
|
8
|
+
config: {},
|
|
9
|
+
schema: {
|
|
10
|
+
[BASE_SCHEMA_FILE]: JSON.stringify(baseSchema, null, 2),
|
|
11
|
+
[SITES_SCHEMA_FILE]: JSON.stringify(sitesSchema, null, 2),
|
|
12
|
+
[BROWSERS_SCHEMA_FILE]: JSON.stringify(browsersSchema, null, 2),
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
export const tree = {
|
|
16
|
+
...initialTree,
|
|
17
|
+
[DATA_FILE]: '',
|
|
18
|
+
lib: {
|
|
19
|
+
node_modules: {
|
|
20
|
+
[PACKAGE_NAME]: {
|
|
21
|
+
dist: {},
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { useCoreActions } from '../actions/core-actions.js';
|
|
2
|
+
import { COMMAND_FALLBACK, DATA_FILE } from '../constants.js';
|
|
3
|
+
const defaultAppData = {
|
|
4
|
+
command: COMMAND_FALLBACK,
|
|
5
|
+
};
|
|
6
|
+
const dataFile = useCoreActions((root) => root[DATA_FILE]);
|
|
7
|
+
const dataRaw = dataFile.read();
|
|
8
|
+
export const appData = dataRaw != null ? JSON.parse(dataRaw) : defaultAppData;
|
|
9
|
+
export function writeAppData(payload) {
|
|
10
|
+
const newData = { ...appData, ...payload };
|
|
11
|
+
dataFile.write(JSON.stringify(newData));
|
|
12
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { load } from 'js-yaml';
|
|
2
|
+
import { useCoreActions } from '../actions/core-actions.js';
|
|
3
|
+
import { initialSites } from './initial-sites.js';
|
|
4
|
+
import { yamlFiles } from '../utils/yaml-files.js';
|
|
5
|
+
import { CONFIG_FILE } from '../constants.js';
|
|
6
|
+
import { sortConfigData } from './sort-config-data.js';
|
|
7
|
+
const configDir = useCoreActions(({ config }) => config);
|
|
8
|
+
function readConfig(option) {
|
|
9
|
+
const found = yamlFiles(CONFIG_FILE(option)).find((fileName) => configDir.exists(fileName));
|
|
10
|
+
return found != null ? configDir.readFile(found) : null;
|
|
11
|
+
}
|
|
12
|
+
const sitesConfigRaw = readConfig('sites');
|
|
13
|
+
const browsersConfigRaw = readConfig('browsers');
|
|
14
|
+
const configData = { sites: {}, browsers: {} };
|
|
15
|
+
if (sitesConfigRaw != null) {
|
|
16
|
+
const { $schema, ...sites } = load(sitesConfigRaw);
|
|
17
|
+
configData.sites = sortConfigData(sites);
|
|
18
|
+
}
|
|
19
|
+
if (browsersConfigRaw != null) {
|
|
20
|
+
const { $schema, ...browsers } = load(browsersConfigRaw);
|
|
21
|
+
const sorted = sortConfigData(browsers);
|
|
22
|
+
// cast null values as empty objects
|
|
23
|
+
configData.browsers = Object.entries(sorted).reduce((acc, [key, browser]) => {
|
|
24
|
+
return { ...acc, [key]: browser === null ? {} : browser };
|
|
25
|
+
}, sorted);
|
|
26
|
+
}
|
|
27
|
+
export { configData };
|
|
28
|
+
export const sitesData = { ...initialSites, ...configData.sites };
|
|
29
|
+
export const browsersData = configData.browsers ?? {};
|
|
30
|
+
export function getProfilesData(browserName) {
|
|
31
|
+
return Object.entries(browsersData[browserName]?.profiles ?? {}).reduce((acc, [key, value]) => ({
|
|
32
|
+
...acc,
|
|
33
|
+
[key]: typeof value === 'string' ? { directory: value } : value,
|
|
34
|
+
}), {});
|
|
35
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { sitesData, browsersData, getProfilesData } from './config-data.js';
|
|
2
|
+
const [siteFallback] = Object.entries(sitesData);
|
|
3
|
+
export const defaultDelimiter = ' ';
|
|
4
|
+
function getDefault(data) {
|
|
5
|
+
const withDefault = Object.entries(data).find(([, item]) => !!item.default);
|
|
6
|
+
if (withDefault != null)
|
|
7
|
+
return withDefault;
|
|
8
|
+
const first = Object.entries(data).at(0);
|
|
9
|
+
if (first != null)
|
|
10
|
+
return first;
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
const getDefaultProfile = (browserName) => {
|
|
14
|
+
const profiles = getProfilesData(browserName);
|
|
15
|
+
return getDefault(profiles);
|
|
16
|
+
};
|
|
17
|
+
export const defaultsData = {
|
|
18
|
+
delimiter: defaultDelimiter,
|
|
19
|
+
site: getDefault(sitesData) ?? siteFallback,
|
|
20
|
+
browser: getDefault(browsersData),
|
|
21
|
+
profile: getDefaultProfile,
|
|
22
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export const initialSites = {
|
|
2
|
+
google: {
|
|
3
|
+
url: 'google.com',
|
|
4
|
+
query: 'search?q=',
|
|
5
|
+
},
|
|
6
|
+
duckduckgo: {
|
|
7
|
+
url: 'duckduckgo.com',
|
|
8
|
+
query: '?q=',
|
|
9
|
+
delimiter: '+',
|
|
10
|
+
alias: ['duck'],
|
|
11
|
+
},
|
|
12
|
+
github: {
|
|
13
|
+
url: 'github.com',
|
|
14
|
+
query: 'search?q=',
|
|
15
|
+
resources: {
|
|
16
|
+
tabs: {
|
|
17
|
+
stars: '?tab=stars',
|
|
18
|
+
repos: '?tab=repositories',
|
|
19
|
+
projects: '?tab=projects',
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
mdn: {
|
|
24
|
+
url: 'developer.mozilla.org',
|
|
25
|
+
query: 'search?q=',
|
|
26
|
+
},
|
|
27
|
+
npm: {
|
|
28
|
+
url: 'npmjs.com',
|
|
29
|
+
query: 'search?q=',
|
|
30
|
+
},
|
|
31
|
+
youtube: {
|
|
32
|
+
url: 'youtube.com',
|
|
33
|
+
query: 'results?search_query=',
|
|
34
|
+
delimiter: '+',
|
|
35
|
+
},
|
|
36
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export function sortConfigData(config) {
|
|
2
|
+
const sortedKeys = Object.keys(config);
|
|
3
|
+
sortedKeys.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
|
|
4
|
+
const [defaultKey] = Object.entries(config).find(([_key, v]) => v?.default) ?? [];
|
|
5
|
+
const sortReducer = (acc, key) => ({
|
|
6
|
+
...acc,
|
|
7
|
+
[key]: config[key],
|
|
8
|
+
});
|
|
9
|
+
return defaultKey != null
|
|
10
|
+
? {
|
|
11
|
+
[defaultKey]: config[defaultKey],
|
|
12
|
+
...sortedKeys
|
|
13
|
+
.filter((key) => key.toLowerCase() !== defaultKey.toLowerCase())
|
|
14
|
+
.reduce(sortReducer, {}),
|
|
15
|
+
}
|
|
16
|
+
: sortedKeys.reduce(sortReducer, {});
|
|
17
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { browsersData } from '../data/config-data.js';
|
|
2
|
+
import { findConfigItem } from './find-config-item.js';
|
|
3
|
+
/**
|
|
4
|
+
* Returns a tuple with the browser's config key and the Item object
|
|
5
|
+
* found in the config by provided name or alias. Otherwise returns undefined
|
|
6
|
+
*/
|
|
7
|
+
export function findBrowser(browserNameOrAlias) {
|
|
8
|
+
return findConfigItem(browserNameOrAlias, browsersData);
|
|
9
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
function withAlias(item) {
|
|
2
|
+
return item instanceof Object && 'alias' in item;
|
|
3
|
+
}
|
|
4
|
+
/**
|
|
5
|
+
* Returns a tuple with the item's config key and the Item object
|
|
6
|
+
* found in the config by provided name or alias. Otherwise returns undefined
|
|
7
|
+
*/
|
|
8
|
+
export function findConfigItem(nameOrAlias, list) {
|
|
9
|
+
return Object.entries(list).find(([key, item]) => {
|
|
10
|
+
// name is list's key
|
|
11
|
+
if (nameOrAlias === key) {
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
// item does not have aliases
|
|
15
|
+
if (!withAlias(item)) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
// name is item's alias
|
|
19
|
+
const { alias } = item;
|
|
20
|
+
return ((Array.isArray(alias) && alias.includes(nameOrAlias)) ||
|
|
21
|
+
(typeof alias === 'string' && alias === nameOrAlias));
|
|
22
|
+
});
|
|
23
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const isPrimitive = (value) => typeof value === 'boolean' ||
|
|
2
|
+
typeof value === 'string' ||
|
|
3
|
+
typeof value === 'number';
|
|
4
|
+
/**
|
|
5
|
+
* @param objectFallbackValue fallback value that is used when a matched property's value is an object
|
|
6
|
+
*/
|
|
7
|
+
export function findNested(target, lookupKey, objectFallbackValue) {
|
|
8
|
+
return Object.keys(target).reduce((result, key) => {
|
|
9
|
+
if (result != null) {
|
|
10
|
+
return result;
|
|
11
|
+
}
|
|
12
|
+
const value = target[key];
|
|
13
|
+
if (key === lookupKey) {
|
|
14
|
+
if (isPrimitive(value)) {
|
|
15
|
+
return value;
|
|
16
|
+
}
|
|
17
|
+
return objectFallbackValue;
|
|
18
|
+
}
|
|
19
|
+
if (typeof value === 'object') {
|
|
20
|
+
return findNested(value, lookupKey, objectFallbackValue);
|
|
21
|
+
}
|
|
22
|
+
return null;
|
|
23
|
+
}, null);
|
|
24
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { getProfilesData } from '../data/config-data.js';
|
|
2
|
+
import { findConfigItem } from './find-config-item.js';
|
|
3
|
+
/**
|
|
4
|
+
* Returns a tuple with the profile's config key and the Profile object
|
|
5
|
+
* if it can be found in the config by the browser name
|
|
6
|
+
* and the profile's name or alias. Otherwise returns undefined
|
|
7
|
+
*/
|
|
8
|
+
export function findProfile(browserName, profileNameOrAlias) {
|
|
9
|
+
const browserProfiles = getProfilesData(browserName);
|
|
10
|
+
return findConfigItem(profileNameOrAlias, browserProfiles);
|
|
11
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { sitesData } from '../data/config-data.js';
|
|
2
|
+
import { initialSites } from '../data/initial-sites.js';
|
|
3
|
+
import { findConfigItem } from './find-config-item.js';
|
|
4
|
+
/**
|
|
5
|
+
* Returns a tuple with the site's config key and the Site object
|
|
6
|
+
* if it can be found in the config by the provided name or alias.
|
|
7
|
+
* Otherwise returns undefined
|
|
8
|
+
*/
|
|
9
|
+
export function findSite(siteArg) {
|
|
10
|
+
if (siteArg == null) {
|
|
11
|
+
return undefined;
|
|
12
|
+
}
|
|
13
|
+
const hasSitesData = Object.keys(sitesData).length > 0;
|
|
14
|
+
return findConfigItem(siteArg, hasSitesData ? sitesData : initialSites);
|
|
15
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { findBrowser } from './find-browser.js';
|
|
2
|
+
/**
|
|
3
|
+
* Returns a browser key from the config if it is found
|
|
4
|
+
* by the provided name or alias, otherwise returns the argument
|
|
5
|
+
*/
|
|
6
|
+
export function getBrowserName(browserNameOrAlias) {
|
|
7
|
+
const [browserName] = findBrowser(browserNameOrAlias) ?? [];
|
|
8
|
+
return browserName ?? browserNameOrAlias;
|
|
9
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { dataArgs } from '../command/args/data-args.js';
|
|
2
|
+
import { defaultsData } from '../data/defaults.js';
|
|
3
|
+
import { findProfile } from './find-profile.js';
|
|
4
|
+
function hasProfile(browserName) {
|
|
5
|
+
return (dataArgs.profile(browserName).length > 0 ||
|
|
6
|
+
defaultsData.profile(browserName) != null);
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Returns a list of tuples with profile's config key
|
|
10
|
+
* and the Profile object for a provided browser name
|
|
11
|
+
*/
|
|
12
|
+
export function getQueryProfiles(browserName) {
|
|
13
|
+
const profiles = [];
|
|
14
|
+
function handleProfile(profileNameOrAlias) {
|
|
15
|
+
const found = findProfile(browserName, profileNameOrAlias);
|
|
16
|
+
profiles.push(found != null
|
|
17
|
+
? found
|
|
18
|
+
: [profileNameOrAlias, { directory: profileNameOrAlias }]);
|
|
19
|
+
}
|
|
20
|
+
if (hasProfile(browserName)) {
|
|
21
|
+
const profileArgs = dataArgs.profile(browserName);
|
|
22
|
+
const defaultProfile = defaultsData.profile(browserName);
|
|
23
|
+
if (profileArgs.length > 0) {
|
|
24
|
+
profileArgs.forEach((profileNameOrAlias) => {
|
|
25
|
+
handleProfile(profileNameOrAlias);
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
else if (defaultProfile != null) {
|
|
29
|
+
const [profileName] = defaultProfile;
|
|
30
|
+
handleProfile(profileName);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return profiles;
|
|
34
|
+
}
|
package/dist/main.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { configArgs } from './command/args/config-args.js';
|
|
3
|
+
import { handleConfig } from './config/handle-config.js';
|
|
4
|
+
import { query } from './query/query.js';
|
|
5
|
+
import { logger } from './utils/logger.js';
|
|
6
|
+
const { config } = configArgs;
|
|
7
|
+
(async function main() {
|
|
8
|
+
if (config) {
|
|
9
|
+
await handleConfig();
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
query();
|
|
13
|
+
})();
|
|
14
|
+
process.on('uncaughtException', (err) => {
|
|
15
|
+
if (err.code !== 'ENOENT') {
|
|
16
|
+
logger.error('An error occurred');
|
|
17
|
+
}
|
|
18
|
+
process.exit(1);
|
|
19
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { findBrowser } from '../helpers/find-browser.js';
|
|
2
|
+
export function getProfilesConfig(browserNameOrAlias) {
|
|
3
|
+
const [, browser] = findBrowser(browserNameOrAlias) ?? [];
|
|
4
|
+
return browser == null
|
|
5
|
+
? undefined
|
|
6
|
+
: Object.entries(browser.profiles ?? {}).reduce((result, [key, profile]) => ({
|
|
7
|
+
...result,
|
|
8
|
+
[key]: typeof profile === 'string' ? profile : profile.directory,
|
|
9
|
+
}), {});
|
|
10
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Browser } from '../api/browser/browser.js';
|
|
2
|
+
import { dataArgs } from '../command/args/data-args.js';
|
|
3
|
+
import { defaultsData } from '../data/defaults.js';
|
|
4
|
+
import { findBrowser } from '../helpers/find-browser.js';
|
|
5
|
+
import { getProfilesConfig } from './get-profiles-config.js';
|
|
6
|
+
const browserArgs = dataArgs.browser();
|
|
7
|
+
export function getQueryBrowsers() {
|
|
8
|
+
if (browserArgs.length === 0) {
|
|
9
|
+
if (defaultsData.browser == null) {
|
|
10
|
+
return [];
|
|
11
|
+
}
|
|
12
|
+
const [defaultBrowserName, defaultBrowser] = defaultsData.browser;
|
|
13
|
+
return [
|
|
14
|
+
[
|
|
15
|
+
defaultBrowserName,
|
|
16
|
+
new Browser(defaultBrowser.appPath ?? defaultBrowserName, {
|
|
17
|
+
profiles: getProfilesConfig(defaultBrowserName),
|
|
18
|
+
}),
|
|
19
|
+
],
|
|
20
|
+
];
|
|
21
|
+
}
|
|
22
|
+
return browserArgs.map((browserNameOrAlias) => {
|
|
23
|
+
const [browserName, browser] = findBrowser(browserNameOrAlias) ?? [
|
|
24
|
+
browserNameOrAlias,
|
|
25
|
+
];
|
|
26
|
+
return [
|
|
27
|
+
browserName,
|
|
28
|
+
new Browser(browser?.appPath ?? browserName, {
|
|
29
|
+
profiles: getProfilesConfig(browserName),
|
|
30
|
+
}),
|
|
31
|
+
];
|
|
32
|
+
});
|
|
33
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Site } from '../api/site/site.js';
|
|
2
|
+
import { dataArgs } from '../command/args/data-args.js';
|
|
3
|
+
import { queryArgs, urlArgs } from '../command/args/query-args.js';
|
|
4
|
+
import { defaultsData, defaultDelimiter } from '../data/defaults.js';
|
|
5
|
+
import { findSite } from '../helpers/find-site.js';
|
|
6
|
+
const [defaultSiteName, defaultSite] = defaultsData.site;
|
|
7
|
+
const siteArgs = dataArgs.site();
|
|
8
|
+
const delimiter = queryArgs.delimiter || defaultDelimiter;
|
|
9
|
+
export function getQuerySites() {
|
|
10
|
+
// create sites based on provided site args
|
|
11
|
+
if (siteArgs.length > 0) {
|
|
12
|
+
return siteArgs.map((siteArg) => {
|
|
13
|
+
const found = findSite(siteArg);
|
|
14
|
+
if (found == null) {
|
|
15
|
+
// site arg can be provided as a URL string
|
|
16
|
+
const site = new Site(siteArg, { delimiter });
|
|
17
|
+
return [siteArg, site];
|
|
18
|
+
}
|
|
19
|
+
const [siteName, site] = found;
|
|
20
|
+
return [
|
|
21
|
+
siteName,
|
|
22
|
+
new Site(site.url, {
|
|
23
|
+
query: site.query,
|
|
24
|
+
delimiter: site.delimiter,
|
|
25
|
+
resources: site.resources,
|
|
26
|
+
}),
|
|
27
|
+
];
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
// do no create sites when there are no value args
|
|
31
|
+
if (queryArgs._.length === 0) {
|
|
32
|
+
return [];
|
|
33
|
+
}
|
|
34
|
+
// create sites when all value args are URLs
|
|
35
|
+
if (urlArgs != null) {
|
|
36
|
+
return urlArgs.map((url) => [url, new Site(url, { delimiter })]);
|
|
37
|
+
}
|
|
38
|
+
// create default site
|
|
39
|
+
return [
|
|
40
|
+
[
|
|
41
|
+
defaultSiteName,
|
|
42
|
+
new Site(defaultSite.url, {
|
|
43
|
+
query: defaultSite.query,
|
|
44
|
+
delimiter: defaultSite.delimiter,
|
|
45
|
+
resources: defaultSite.resources,
|
|
46
|
+
}),
|
|
47
|
+
],
|
|
48
|
+
];
|
|
49
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { dataArgs } from '../command/args/data-args.js';
|
|
2
|
+
import { queryArgs, urlArgs } from '../command/args/query-args.js';
|
|
3
|
+
import { findNested } from '../helpers/find-nested.js';
|
|
4
|
+
const { _: args, resource, http } = queryArgs;
|
|
5
|
+
const siteArgs = dataArgs.site();
|
|
6
|
+
const portArgs = dataArgs.port();
|
|
7
|
+
const port = portArgs.length === 0 ? undefined : portArgs;
|
|
8
|
+
// if there are no site args and all value args are URLs,
|
|
9
|
+
// remove URL args from keywords list because they are used as sites
|
|
10
|
+
const keywords = args.filter((keyword) => siteArgs.length > 0 || !urlArgs || !urlArgs.includes(keyword));
|
|
11
|
+
function handleResource(site, resourceValue) {
|
|
12
|
+
const splitter = '::';
|
|
13
|
+
function findResourceByValue(resources) {
|
|
14
|
+
return findNested(resources, resourceValue, resourceValue);
|
|
15
|
+
}
|
|
16
|
+
return site.resource((config = {}) => {
|
|
17
|
+
// NOTE: resource object has a property key containing the splitter
|
|
18
|
+
const foundResourceValue = findResourceByValue(config);
|
|
19
|
+
if (foundResourceValue != null) {
|
|
20
|
+
return foundResourceValue;
|
|
21
|
+
}
|
|
22
|
+
const [resourceKey] = resourceValue.split(splitter);
|
|
23
|
+
const isEscaped = resourceKey.startsWith('/');
|
|
24
|
+
// do not search in config if resource key starts with slash
|
|
25
|
+
return isEscaped
|
|
26
|
+
? resourceKey.slice(1)
|
|
27
|
+
: (findNested(config, resourceKey, resourceKey) ?? resourceKey);
|
|
28
|
+
}, {
|
|
29
|
+
path(config = {}) {
|
|
30
|
+
const foundResource = findResourceByValue(config);
|
|
31
|
+
// Relates to the NOTE in the above callback
|
|
32
|
+
// Add path found by splitted path key only if resource does not include the splitter
|
|
33
|
+
if (foundResource == null) {
|
|
34
|
+
const pathKeys = resourceValue.split(splitter).slice(1);
|
|
35
|
+
if (pathKeys.length > 0) {
|
|
36
|
+
const result = pathKeys
|
|
37
|
+
.reduce((acc, pathKey) => {
|
|
38
|
+
const isEscaped = pathKey.startsWith('/');
|
|
39
|
+
acc.push(
|
|
40
|
+
// do not search in config if path key starts with slash
|
|
41
|
+
isEscaped
|
|
42
|
+
? pathKey.slice(1)
|
|
43
|
+
: (findNested(config, pathKey, pathKey) ?? pathKey));
|
|
44
|
+
return acc;
|
|
45
|
+
}, [])
|
|
46
|
+
.reduce((acc, value) => {
|
|
47
|
+
return `${acc}${value.startsWith('?') ? value : `/${value}`}`;
|
|
48
|
+
}, '');
|
|
49
|
+
return [...keywords, result];
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return keywords;
|
|
53
|
+
},
|
|
54
|
+
port,
|
|
55
|
+
unsecureHttp: http,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
function handleQueryPath(config = { main: '/' }) {
|
|
59
|
+
function getQuery(search) {
|
|
60
|
+
return typeof config !== 'string'
|
|
61
|
+
? (findNested(config, search, search) ?? search)
|
|
62
|
+
: search;
|
|
63
|
+
}
|
|
64
|
+
const { query } = queryArgs;
|
|
65
|
+
if (query == null) {
|
|
66
|
+
return typeof config === 'string' ? config : config.main;
|
|
67
|
+
}
|
|
68
|
+
if (Array.isArray(query)) {
|
|
69
|
+
return query.map((s) => getQuery(s));
|
|
70
|
+
}
|
|
71
|
+
return getQuery(query);
|
|
72
|
+
}
|
|
73
|
+
export function getUrls(site) {
|
|
74
|
+
if (resource != null) {
|
|
75
|
+
return Array.isArray(resource)
|
|
76
|
+
? resource.map((r) => handleResource(site, r)).flat()
|
|
77
|
+
: handleResource(site, resource);
|
|
78
|
+
}
|
|
79
|
+
return site.search(keywords.join(' '), {
|
|
80
|
+
queryPath: handleQueryPath,
|
|
81
|
+
port,
|
|
82
|
+
split: queryArgs.split,
|
|
83
|
+
unsecureHttp: queryArgs.http,
|
|
84
|
+
});
|
|
85
|
+
}
|