Skip to content

Commit

Permalink
feat: exposed consy keys
Browse files Browse the repository at this point in the history
  • Loading branch information
ScarletFlash committed Nov 10, 2024
1 parent a777463 commit 5c2ed08
Show file tree
Hide file tree
Showing 35 changed files with 157 additions and 53 deletions.
10 changes: 10 additions & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"recommendations": [
"Vercel.turbo-vsc",
"bierner.markdown-mermaid",
"bradlc.vscode-tailwindcss",
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"redhat.vscode-yaml"
]
}
7 changes: 7 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"references.preferredLocation": "view",
"turbo.useLocalTurbo": true,
"typescript.check.npmIsInstalled": true,
"typescript.enablePromptUseWorkspaceTsdk": true,
"typescript.tsdk": "./node_modules/typescript/lib"
}
10 changes: 5 additions & 5 deletions core/src/accessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export class Acessor<P, K extends string = string> {
}

public mount(key: K, payload: P): void {
if (Acessor.#isHostWithTarget(this.#host, key)) {
if (this.isMounted(key)) {
throw new Error(`Key ${key} is already mounted. Either unmount it first or use a different key.`);
}

Expand All @@ -22,20 +22,20 @@ export class Acessor<P, K extends string = string> {
}

public unmount(key: K): void {
if (!Acessor.#isHostWithTarget(this.#host, key)) {
if (!this.isMounted(key)) {
throw new Error(`Key ${key} is not mounted, so it cannot be unmounted.`);
}
delete this.#host[key];
}

public getValue(key: K): P {
if (!Acessor.#isHostWithTarget<P, K>(this.#host, key)) {
if (!this.isMounted(key)) {
throw new Error(`Key ${key} is not mounted, so it cannot be accessed.`);
}
return this.#host[key];
}

static #isHostWithTarget<P, K extends string>(host: Host, key: K): host is Host & Target<P, K> {
return key in host;
public isMounted(key: K): boolean {
return key in this.#host;
}
}
37 changes: 33 additions & 4 deletions core/src/consy.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,54 @@
import { CommandDefinition, InteractiveObject } from '@consy/declarations';
import { CommandDefinition, EXPOSED_KEYS_PROPERTY_NAME, InteractiveObject } from '@consy/declarations';
import { Acessor } from './accessor';
import { InteractiveObjectBuilder } from './interactive-object-builder';

export class Consy<K extends string = string> {
readonly #interactor: InteractiveObjectBuilder = new InteractiveObjectBuilder();

readonly #accessor: Acessor<InteractiveObject, K> = new Acessor<InteractiveObject, K>(window);
readonly #interactiveObjectAccessor: Acessor<InteractiveObject, K> = new Acessor<InteractiveObject, K>(window);
readonly #exposedKeysAccessor: Acessor<string[], string> = new Acessor<string[], string>(window);

readonly #key: K;

constructor(key: K) {
if (key.length === 0) {
throw new Error('Key cannot be an empty string.');
}

this.#key = key;
}

public mount(): this {
this.#accessor.mount(this.#key, this.#interactor.payload);
this.#interactiveObjectAccessor.mount(this.#key, this.#interactor.payload);

const isExposedKeysPropertyMounted: boolean = this.#exposedKeysAccessor.isMounted(EXPOSED_KEYS_PROPERTY_NAME);
if (!isExposedKeysPropertyMounted) {
this.#exposedKeysAccessor.mount(EXPOSED_KEYS_PROPERTY_NAME, []);
}
const rawExposedKeys: string[] = this.#exposedKeysAccessor.getValue(EXPOSED_KEYS_PROPERTY_NAME);
if (rawExposedKeys.includes(this.#key)) {
throw new Error(`The key "${this.#key}" is already used by a different instance of Consy.`);
}
rawExposedKeys.push(this.#key);

return this;
}

public unmount(): this {
this.#accessor.unmount(this.#key);
this.#interactiveObjectAccessor.unmount(this.#key);

const isExposedKeysPropertyMounted: boolean = this.#exposedKeysAccessor.isMounted(EXPOSED_KEYS_PROPERTY_NAME);
if (!isExposedKeysPropertyMounted) {
throw new Error('The exposed keys property is not mounted, so it cannot be unmounted.');
}
const rawExposedKeys: string[] = this.#exposedKeysAccessor.getValue(EXPOSED_KEYS_PROPERTY_NAME);

const keyIndex: number = rawExposedKeys.indexOf(this.#key);
if (keyIndex === -1) {
throw new Error(`The key "${this.#key}" is not used by any instance of Consy.`);
}
rawExposedKeys.splice(keyIndex, 1);

return this;
}

Expand Down
2 changes: 1 addition & 1 deletion core/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@
"outDir": "./tsc-out"
},
"extends": "@consy/configs/typescript/browser.json",
"include": ["src"]
"include": ["./src"]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const EXPOSED_KEYS_PROPERTY_NAME: string = '__consy_exposed-keys';
21 changes: 12 additions & 9 deletions declarations/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
export * from './callable-command';
export * from './command-definition';
export * from './interactive-object';
export * from './parameterizable-command';
export * from './non-parameterizable-command';
export * from './command-param-definition';
export * from './command-param-type';
export * from './command-params';
export * from './command-params-definition';
export * from './constants/exposed-keys-property-name.const';
export * from './types/callable-command.type';
export * from './types/command-definition.type';
export * from './types/interactive-object.type';
export * from './types/parameterizable-command.type';
export * from './types/non-parameterizable-command.type';
export * from './types/command-param-definition.type';
export * from './types/command-param-type.type';
export * from './types/command-params.type';
export * from './types/command-params-definition.type';
export * from './types/promise-resolver.type';
export * from './types/promise-rejector.type';
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { AnyFunction } from './any-function';
import { SyncOrAsyncFunction } from './sync-or-async-function';
import { AnyFunction } from './any-function.type';
import { SyncOrAsyncFunction } from './sync-or-async-function.type';

export interface CommandDefinitionBase<C extends AnyFunction> {
readonly name: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { NonParameterizableCommand } from './non-parameterizable-command';
import { ParameterizableCommand } from './parameterizable-command';
import { NonParameterizableCommand } from './non-parameterizable-command.type';
import { ParameterizableCommand } from './parameterizable-command.type';

export type CommandDefinition = NonParameterizableCommand | ParameterizableCommand;
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CommandParamType } from './command-param-type';
import { CommandParamType } from './command-param-type.type';

export interface CommandParamDefinitionBase<T extends CommandParamType = CommandParamType> {
readonly type: T;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { CommandParamDefinitionBase } from './command-param-definition-base';
import { CommandParamType } from './command-param-type';
import { CommandParamDefinitionBase } from './command-param-definition-base.type';
import { CommandParamType } from './command-param-type.type';

type StringParamDefinition = CommandParamDefinitionBase<CommandParamType.String>;

Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CommandParamDefinition } from './command-param-definition';
import { CommandParamDefinition } from './command-param-definition.type';

export interface CommandParamsDefinition {
readonly [key: string]: CommandParamDefinition;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { CommandParamDefinitionBase } from './command-param-definition-base';
import { CommandParamType } from './command-param-type';
import { CommandParamsDefinition } from './command-params-definition';
import { CommandParamDefinitionBase } from './command-param-definition-base.type';
import { CommandParamType } from './command-param-type.type';
import { CommandParamsDefinition } from './command-params-definition.type';

type CommandParamDefinitionType<T extends CommandParamDefinitionBase> = T['type'];

Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import { CommandDefinitionBase } from './command-definition-base';
import { CommandDefinitionBase } from './command-definition-base.type';

export type NonParameterizableCommand = CommandDefinitionBase<() => void>;
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { CommandDefinitionBase } from './command-definition-base';
import { CommandParams } from './command-params';
import { CommandParamsDefinition } from './command-params-definition';
import { CommandDefinitionBase } from './command-definition-base.type';
import { CommandParams } from './command-params.type';
import { CommandParamsDefinition } from './command-params-definition.type';

export interface ParameterizableCommand<D extends CommandParamsDefinition = CommandParamsDefinition>
extends CommandDefinitionBase<(params: CommandParams<D>) => void> {
Expand Down
1 change: 1 addition & 0 deletions declarations/src/types/promise-rejector.type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type PromiseRejector<R = unknown> = (reason: R) => void;
1 change: 1 addition & 0 deletions declarations/src/types/promise-resolver.type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type PromiseResolver<T = unknown> = (payload: T) => void;
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AnyFunction } from './any-function';
import { AnyFunction } from './any-function.type';

/** @private */
export type SyncOrAsyncFunction<F extends AnyFunction> = F extends (...args: infer A) => infer R
Expand Down
2 changes: 1 addition & 1 deletion declarations/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@
"outDir": "./tsc-out"
},
"extends": "@consy/configs/typescript/browser.json",
"include": ["src"]
"include": ["./src"]
}
2 changes: 1 addition & 1 deletion dist/tsconfig.build.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@
"outDir": "./tsc-out"
},
"extends": "@consy/configs/typescript/browser.json",
"include": ["src"]
"include": ["./src"]
}
2 changes: 1 addition & 1 deletion examples/tsconfig.build.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@
"outDir": "./tsc-out"
},
"extends": "@consy/configs/typescript/browser.json",
"include": ["src"]
"include": ["./src"]
}
19 changes: 10 additions & 9 deletions extension/build.script.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ const DEFAULT_CHARSET: 'utf8' = 'utf8';

const RESULT_BUNDLE_PATH: string = resolve(__dirname, 'unpacked-extension');

const ENTRY_POINT_FILE_NAME: string = 'index';
const ENTRY_POINT_PATH: string = resolve(__dirname, 'src', `${ENTRY_POINT_FILE_NAME}.ts`);
const LAYOUT_ENTRY_POINT_FILE_NAME: string = `${ENTRY_POINT_FILE_NAME}.html`;
const GLOBAL_STYLES_ENTRY_POINT_FILE_NAME: string = `${ENTRY_POINT_FILE_NAME}.css`;
const POPUP_FILE_NAME: string = 'popup';
const POPUP_SCRIPT_PATH: string = resolve(__dirname, 'src', `${POPUP_FILE_NAME}.ts`);
const POPUP_LAYOUT_FILE_NAME: string = `${POPUP_FILE_NAME}.html`;
const POPUP_STYLES_FILE_NAME: string = `${POPUP_FILE_NAME}.css`;

const BUILD_TS_CONFIG_PATH: string = resolve(__dirname, 'tsconfig.build.json');

Expand All @@ -25,10 +25,10 @@ const EXTENSION_MANIFEST_RESULT_FILE_PATH: string = resolve(RESULT_BUNDLE_PATH,
const SOURCE_CODE_DIRECTORY_NAME: string = 'src';
const SOURCE_CODE_DIRECTORY_PATH: string = resolve(__dirname, SOURCE_CODE_DIRECTORY_NAME);

const ROOT_LAYOUT_ENTRY_POINT: string = resolve(SOURCE_CODE_DIRECTORY_PATH, LAYOUT_ENTRY_POINT_FILE_NAME);
const GLOBAL_STYLES_ENTRY_POINT: string = resolve(SOURCE_CODE_DIRECTORY_PATH, GLOBAL_STYLES_ENTRY_POINT_FILE_NAME);
const ROOT_LAYOUT_ENTRY_POINT: string = resolve(SOURCE_CODE_DIRECTORY_PATH, POPUP_LAYOUT_FILE_NAME);
const GLOBAL_STYLES_ENTRY_POINT: string = resolve(SOURCE_CODE_DIRECTORY_PATH, POPUP_STYLES_FILE_NAME);

const RESULT_BUNDLE_GLOBAL_STYLES_ENTRY_POINT: string = join(RESULT_BUNDLE_PATH, GLOBAL_STYLES_ENTRY_POINT_FILE_NAME);
const RESULT_BUNDLE_GLOBAL_STYLES_ENTRY_POINT: string = join(RESULT_BUNDLE_PATH, POPUP_STYLES_FILE_NAME);

const SOURCE_ASSETS_DIRECTORY_PATH: string = resolve(__dirname, 'node_modules/@consy/assets/');
const RESULT_BUNDLE_ASSETS_DIRECTORY_PATH: string = join(RESULT_BUNDLE_PATH, 'assets');
Expand All @@ -54,7 +54,7 @@ async function generateCss({ contentPaths, globalStylesOutput, globalStylesInput
await mkdir(RESULT_BUNDLE_PATH, { recursive: true });

new Set([
ENTRY_POINT_PATH,
POPUP_SCRIPT_PATH,
BUILD_TS_CONFIG_PATH,
PACKAGE_MANIFEST_SOURCE_FILE_PATH,
GLOBAL_STYLES_ENTRY_POINT,
Expand Down Expand Up @@ -88,7 +88,7 @@ async function generateCss({ contentPaths, globalStylesOutput, globalStylesInput
tsconfig: BUILD_TS_CONFIG_PATH,
bundle: true,
minify: true,
splitting: true,
splitting: false,
format: 'esm',
treeShaking: true,
charset: DEFAULT_CHARSET,
Expand All @@ -115,6 +115,7 @@ async function generateCss({ contentPaths, globalStylesOutput, globalStylesInput
const modifiedManifestContent: string = rawManifestContent
.replaceAll(`${SOURCE_CODE_DIRECTORY_NAME}/`, '')
.replaceAll('node_modules/@consy/assets/', 'assets/')
.replaceAll('.ts"', '.js"')
.replace(`"$schema": "https://json.schemastore.org/chrome-manifest",`, '');

await writeFile(EXTENSION_MANIFEST_RESULT_FILE_PATH, modifiedManifestContent, { encoding: DEFAULT_CHARSET });
Expand Down
6 changes: 5 additions & 1 deletion extension/manifest.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
{
"$schema": "https://json.schemastore.org/chrome-manifest",
"action": {
"default_popup": "src/index.html",
"default_popup": "src/popup.html",
"default_icon": {
"16": "node_modules/@consy/assets/icon-16.png",
"24": "node_modules/@consy/assets/icon-24.png",
"32": "node_modules/@consy/assets/icon-32.png"
}
},
"background": {
"service_worker": "src/service-worker.ts"
},
"description": "Consy UI extension",
"manifest_version": 3,
"name": "Consy",
"permissions": ["scripting", "activeTab"],
"version": "0.0.1"
}
3 changes: 3 additions & 0 deletions extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
"formatter__fix": "prettier --config node_modules/@consy/configs/prettier/config.json --ignore-path node_modules/@consy/configs/prettier/ignore --cache --cache-location .prettiercache --cache-strategy content --write .",
"build": "ts-node --project tsconfig.scripts.json ./build.script.ts"
},
"dependencies": {
"@consy/declarations": "workspace:*"
},
"devDependencies": {
"tailwindcss": "catalog:build-tools",
"ts-node": "catalog:build-tools",
Expand Down
File renamed without changes.
4 changes: 2 additions & 2 deletions extension/src/index.html → extension/src/popup.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
<head>
<link
rel="stylesheet"
href="index.css"
href="popup.css"
/>
</head>

<body>
<h1>Hello Extensions</h1>
<script src="index.ts"></script>
<script src="popup.ts"></script>
</body>
</html>
File renamed without changes.
38 changes: 38 additions & 0 deletions extension/src/service-worker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { PromiseRejector } from '@consy/declarations';

function getActiveTab(): Promise<chrome.tabs.Tab> {
return new Promise((resolve: PromiseRejector<chrome.tabs.Tab>, reject: PromiseRejector<Error>) => {
chrome.tabs.query({ active: true, currentWindow: true }, (tabs: chrome.tabs.Tab[]) => {
const firstActiveTab: chrome.tabs.Tab | undefined = tabs[0];
if (firstActiveTab === undefined) {
return reject(new Error('No active tab found'));
}

resolve(firstActiveTab);
});
});
}

Promise.resolve()
.then(async () => {
const { id: tabId, url: activeTabUrl }: chrome.tabs.Tab = await getActiveTab();

if (activeTabUrl === undefined || activeTabUrl.startsWith('chrome://')) {
return;
}

if (tabId === undefined) {
throw new Error('No active tab ID found');
}

await chrome.scripting.executeScript({
target: { tabId, allFrames: true },
func: () => {
console.log('injected script');
}
});
console.log('script injected in all frames');
})
.catch((error: unknown) => {
console.error(error instanceof Error ? error.message : 'Unknown error');
});
6 changes: 4 additions & 2 deletions extension/tsconfig.build.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": {
"outDir": "./tsc-out"
"outDir": "./tsc-out",
"types": ["chrome-types"],
"declaration": false
},
"extends": "@consy/configs/typescript/browser.json",
"include": ["src"]
"include": ["./src"]
}
4 changes: 4 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 5c2ed08

Please sign in to comment.