@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.
Files changed (63) hide show
  1. package/LICENSE +16 -0
  2. package/README.md +800 -0
  3. package/dist/actions/core-actions.js +6 -0
  4. package/dist/actions/npm-actions.js +38 -0
  5. package/dist/actions/permission-actions.js +21 -0
  6. package/dist/api/browser/browser.js +111 -0
  7. package/dist/api/browser/browser.types.js +1 -0
  8. package/dist/api/matchers/matchers.js +9 -0
  9. package/dist/api/site/site.js +248 -0
  10. package/dist/api/site/site.types.js +1 -0
  11. package/dist/api/utils/extract-protocol.js +10 -0
  12. package/dist/api/utils/remove-protocol.js +8 -0
  13. package/dist/api/utils/return-type-guard.js +7 -0
  14. package/dist/api/utils/slash.js +21 -0
  15. package/dist/command/args/config-args.js +9 -0
  16. package/dist/command/args/data-args.js +110 -0
  17. package/dist/command/args/invalid-args.js +11 -0
  18. package/dist/command/args/query-args.js +121 -0
  19. package/dist/command/args/validate-args.js +126 -0
  20. package/dist/command/options.js +58 -0
  21. package/dist/config/config-file.js +66 -0
  22. package/dist/config/config-flags.js +42 -0
  23. package/dist/config/file-editor.js +26 -0
  24. package/dist/config/handle-config.js +12 -0
  25. package/dist/constants.js +15 -0
  26. package/dist/create-app/main.js +121 -0
  27. package/dist/create-app/paths.js +24 -0
  28. package/dist/create-app/schema/base.json +21 -0
  29. package/dist/create-app/schema/browsers.json +60 -0
  30. package/dist/create-app/schema/sites.json +71 -0
  31. package/dist/create-app/script-contents.js +18 -0
  32. package/dist/create-app/tree.js +25 -0
  33. package/dist/data/app-data.js +12 -0
  34. package/dist/data/config-data.js +35 -0
  35. package/dist/data/defaults.js +22 -0
  36. package/dist/data/initial-sites.js +36 -0
  37. package/dist/data/sort-config-data.js +17 -0
  38. package/dist/helpers/find-browser.js +9 -0
  39. package/dist/helpers/find-config-item.js +23 -0
  40. package/dist/helpers/find-nested.js +24 -0
  41. package/dist/helpers/find-profile.js +11 -0
  42. package/dist/helpers/find-site.js +15 -0
  43. package/dist/helpers/get-browser-name.js +9 -0
  44. package/dist/helpers/get-query-profiles.js +34 -0
  45. package/dist/main.js +19 -0
  46. package/dist/query/get-profiles-config.js +10 -0
  47. package/dist/query/get-query-browsers.js +33 -0
  48. package/dist/query/get-query-sites.js +49 -0
  49. package/dist/query/get-urls.js +85 -0
  50. package/dist/query/open-urls.js +30 -0
  51. package/dist/query/print-query.js +24 -0
  52. package/dist/query/query.js +19 -0
  53. package/dist/types/arg.types.js +1 -0
  54. package/dist/types/config.types.js +1 -0
  55. package/dist/types/primitive.type.js +1 -0
  56. package/dist/types/query.types.js +1 -0
  57. package/dist/types/utility.types.js +1 -0
  58. package/dist/utils/get-package-info.js +10 -0
  59. package/dist/utils/logger.js +15 -0
  60. package/dist/utils/parse-data.js +15 -0
  61. package/dist/utils/transform-text.js +7 -0
  62. package/dist/utils/yaml-files.js +6 -0
  63. 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
+ }