initial commit
This commit is contained in:
21
node_modules/unctx/LICENSE
generated
vendored
Normal file
21
node_modules/unctx/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 - Pooya Parsa <pooya@pi0.io>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
198
node_modules/unctx/README.md
generated
vendored
Normal file
198
node_modules/unctx/README.md
generated
vendored
Normal file
@@ -0,0 +1,198 @@
|
||||
# 🍦 unctx
|
||||
|
||||
> Composition-api in Vanilla js
|
||||
|
||||
[![npm version][npm-v-src]][npm-v-href]
|
||||
[![npm downloads][npm-dm-src]][npm-dm-href]
|
||||
[![package phobia][packagephobia-src]][packagephobia-href]
|
||||
[![bundle phobia][bundlephobia-src]][bundlephobia-href]
|
||||
[![codecov][codecov-src]][codecov-href]
|
||||
|
||||
## What is it?
|
||||
|
||||
[Vue.js](https://vuejs.org) introduced an amazing pattern called [Composition API](https://v3.vuejs.org/guide/composition-api-introduction.html) that allows organizing complex logic by splitting it into reusable functions and grouping in logical order. `unctx` allows easily implementing composition api pattern in your javascript libraries without hassle.
|
||||
|
||||
## Integration
|
||||
|
||||
In your **awesome** library:
|
||||
|
||||
```bash
|
||||
yarn add unctx
|
||||
# or
|
||||
npm install unctx
|
||||
```
|
||||
|
||||
```js
|
||||
import { createContext } from 'unctx'
|
||||
|
||||
const ctx = createContext()
|
||||
|
||||
export const useAwesome = ctx.use
|
||||
|
||||
// ...
|
||||
ctx.call({ test: 1 }, () => {
|
||||
// This is similar to vue setup function
|
||||
// Any function called here, can use `useAwesome` to get { test: 1 }
|
||||
})
|
||||
```
|
||||
|
||||
User code:
|
||||
|
||||
```js
|
||||
import { useAwesome } from 'awesome-lib'
|
||||
|
||||
// ...
|
||||
function setup() {
|
||||
const ctx = useAwesome()
|
||||
}
|
||||
```
|
||||
|
||||
**Note:** when no context is presented `ctx.use` will throw an error. Use `ctx.tryUse` for tolerant usages (return nullable context).
|
||||
|
||||
## Using Namespaces
|
||||
|
||||
To avoid issues with multiple version of library, `unctx` provides a safe global namespace to access context by key (kept in [`globalThis`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/globalThis)). **Important:** Please use a verbose name for key to avoid conflict with other js libraries. Using npm package name is recommended. Using symbols has no effect since it still causes multiple context issue.
|
||||
|
||||
```js
|
||||
import { useContext, getContext } from 'unctx'
|
||||
|
||||
const useAwesome = useContext('awesome-lib')
|
||||
|
||||
// or
|
||||
// const awesomeContext = getContext('awesome-lib')
|
||||
```
|
||||
|
||||
You can also create your own internal namespace with `createNamespace` utility for more advanced use cases.
|
||||
|
||||
## Singleton Pattern
|
||||
|
||||
If you are sure it is safe to use a shared instance (not depending to request), you can also use `ctx.set` and `ctx.unset` for a [singleton pattern](https://en.wikipedia.org/wiki/Singleton_pattern).
|
||||
|
||||
**Note:** You cannot combine `set` with `call`. Always use `unset` before replacing instance otherwise you will get `Context conflict` error.
|
||||
|
||||
```js
|
||||
import { createContext } from 'unctx'
|
||||
|
||||
const ctx = createContext()
|
||||
ctx.set(new Awesome())
|
||||
|
||||
// Replacing instance without unset
|
||||
// ctx.set(new Awesome(), true)
|
||||
|
||||
export const useAwesome = ctx.use
|
||||
```
|
||||
|
||||
## TypeScript
|
||||
|
||||
A generic type exists on all utilities to be set for instance/context type:
|
||||
|
||||
```ts
|
||||
// Return type of useAwesome is Awesome | null
|
||||
const { use: useAwesome } = createContext<Awesome>()
|
||||
```
|
||||
|
||||
## Async Context
|
||||
|
||||
Normally, using context is only possible before first await statement:
|
||||
|
||||
```js
|
||||
async function setup() {
|
||||
console.log(useAwesome()) // Returns context
|
||||
await new Promise(resolve => setTimeout(resolve, 1000))
|
||||
console.log(useAwesome()) // Returns null
|
||||
}
|
||||
```
|
||||
|
||||
A simple workaround, is caching context before first await and use it directly:
|
||||
|
||||
```js
|
||||
async function setup() {
|
||||
const ctx = useAwesome()
|
||||
await new Promise(resolve => setTimeout(resolve, 1000))
|
||||
console.log(ctx) // We can directly access cached version of ctx
|
||||
}
|
||||
```
|
||||
|
||||
However, this is not always as easy as making a variable when using nested composables.
|
||||
|
||||
Unctx provides a better solution that transforms async to automatically restore context after each await call. This requires using a bundler such as Rollup, Vite or Webpack.
|
||||
|
||||
Import and register transform plugin:
|
||||
|
||||
```js
|
||||
import { unctxPlugin } from 'unctx/plugin'
|
||||
|
||||
// Rollup
|
||||
// TODO: Add to rollup configuration
|
||||
unctxPlugin.rollup()
|
||||
|
||||
// Vite
|
||||
// TODO: Add to vite configuration
|
||||
unctxPlugin.vite()
|
||||
|
||||
// Webpack
|
||||
// TODO: Add to webpack configuration
|
||||
unctxPlugin.webpack()
|
||||
```
|
||||
|
||||
Use `ctx.callAsync` instead of `ctx.call`:
|
||||
|
||||
```js
|
||||
await ctx.callAsync('test', setup)
|
||||
```
|
||||
|
||||
Any async function that requires context, should be wrapped with `withAsyncContext`:
|
||||
|
||||
```js
|
||||
import { withAsyncContext } from 'unctx'
|
||||
|
||||
const setup = withAsyncContext(async () => {
|
||||
console.log(useAwesome()) // Returns context
|
||||
await new Promise(resolve => setTimeout(resolve, 1000))
|
||||
console.log(useAwesome()) // Still returns context with dark magic!
|
||||
})
|
||||
```
|
||||
|
||||
## Under the hood
|
||||
|
||||
Composition of functions is possible using temporary context injection. When calling `ctx.call(instance, cb)`, `instance` argument will be stored in a temporary variable then `cb` is called. Any function inside `cb`, can then implicitly access instance by using `ctx.use` (or `useAwesome`)
|
||||
|
||||
## Pitfalls
|
||||
|
||||
**context can be only used before first await**:
|
||||
|
||||
Please check Async context section.
|
||||
|
||||
**`Context conflict` error**:
|
||||
|
||||
In your library, you should only keep one `call()` running at a time (unless calling with same reference for first argument)
|
||||
|
||||
For instance this makes an error:
|
||||
|
||||
```js
|
||||
ctx.call({ test: 1 }, () => {
|
||||
ctx.call({ test: 2 }, () => {
|
||||
// Throws error!
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
MIT. Made with 💖
|
||||
|
||||
<!-- Refs -->
|
||||
[npm-v-src]: https://flat.badgen.net/npm/v/unctx/latest
|
||||
[npm-v-href]: https://npmjs.com/package/unctx
|
||||
|
||||
[npm-dm-src]: https://flat.badgen.net/npm/dm/unctx
|
||||
[npm-dm-href]: https://npmjs.com/package/unctx
|
||||
|
||||
[packagephobia-src]: https://flat.badgen.net/packagephobia/install/unctx
|
||||
[packagephobia-href]: https://packagephobia.now.sh/result?p=unctx
|
||||
|
||||
[bundlephobia-src]: https://flat.badgen.net/bundlephobia/min/unctx
|
||||
[bundlephobia-href]: https://bundlephobia.com/result?p=unctx
|
||||
|
||||
[codecov-src]: https://flat.badgen.net/codecov/c/github/unjs/unctx/master
|
||||
[codecov-href]: https://codecov.io/gh/unjs/unctx
|
||||
116
node_modules/unctx/dist/index.cjs
generated
vendored
Normal file
116
node_modules/unctx/dist/index.cjs
generated
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
'use strict';
|
||||
|
||||
function createContext() {
|
||||
let currentInstance;
|
||||
let isSingleton = false;
|
||||
const checkConflict = (instance) => {
|
||||
if (currentInstance && currentInstance !== instance) {
|
||||
throw new Error("Context conflict");
|
||||
}
|
||||
};
|
||||
return {
|
||||
use: () => {
|
||||
if (currentInstance === void 0) {
|
||||
throw new Error("Context is not available");
|
||||
}
|
||||
return currentInstance;
|
||||
},
|
||||
tryUse: () => {
|
||||
return currentInstance;
|
||||
},
|
||||
set: (instance, replace) => {
|
||||
if (!replace) {
|
||||
checkConflict(instance);
|
||||
}
|
||||
currentInstance = instance;
|
||||
isSingleton = true;
|
||||
},
|
||||
unset: () => {
|
||||
currentInstance = void 0;
|
||||
isSingleton = false;
|
||||
},
|
||||
call: (instance, callback) => {
|
||||
checkConflict(instance);
|
||||
currentInstance = instance;
|
||||
try {
|
||||
return callback();
|
||||
} finally {
|
||||
if (!isSingleton) {
|
||||
currentInstance = void 0;
|
||||
}
|
||||
}
|
||||
},
|
||||
async callAsync(instance, callback) {
|
||||
currentInstance = instance;
|
||||
const onRestore = () => {
|
||||
currentInstance = instance;
|
||||
};
|
||||
const onLeave = () => currentInstance === instance ? onRestore : void 0;
|
||||
asyncHandlers.add(onLeave);
|
||||
try {
|
||||
const r = callback();
|
||||
if (!isSingleton) {
|
||||
currentInstance = void 0;
|
||||
}
|
||||
return await r;
|
||||
} finally {
|
||||
asyncHandlers.delete(onLeave);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
function createNamespace() {
|
||||
const contexts = {};
|
||||
return {
|
||||
get(key) {
|
||||
if (!contexts[key]) {
|
||||
contexts[key] = createContext();
|
||||
}
|
||||
contexts[key];
|
||||
return contexts[key];
|
||||
}
|
||||
};
|
||||
}
|
||||
const _globalThis = typeof globalThis !== "undefined" ? globalThis : typeof self !== "undefined" ? self : typeof global !== "undefined" ? global : typeof window !== "undefined" ? window : {};
|
||||
const globalKey = "__unctx__";
|
||||
const defaultNamespace = _globalThis[globalKey] || (_globalThis[globalKey] = createNamespace());
|
||||
const getContext = (key) => defaultNamespace.get(key);
|
||||
const useContext = (key) => getContext(key).use;
|
||||
const asyncHandlersKey = "__unctx_async_handlers__";
|
||||
const asyncHandlers = _globalThis[asyncHandlersKey] || (_globalThis[asyncHandlersKey] = /* @__PURE__ */ new Set());
|
||||
function executeAsync(function_) {
|
||||
const restores = [];
|
||||
for (const leaveHandler of asyncHandlers) {
|
||||
const restore2 = leaveHandler();
|
||||
if (restore2) {
|
||||
restores.push(restore2);
|
||||
}
|
||||
}
|
||||
const restore = () => {
|
||||
for (const restore2 of restores) {
|
||||
restore2();
|
||||
}
|
||||
};
|
||||
let awaitable = function_();
|
||||
if (awaitable && typeof awaitable === "object" && "catch" in awaitable) {
|
||||
awaitable = awaitable.catch((error) => {
|
||||
restore();
|
||||
throw error;
|
||||
});
|
||||
}
|
||||
return [awaitable, restore];
|
||||
}
|
||||
function withAsyncContext(function_, transformed) {
|
||||
if (!transformed) {
|
||||
console.warn("[unctx] `withAsyncContext` needs transformation for async context support in", function_, "\n", function_.toString());
|
||||
}
|
||||
return function_;
|
||||
}
|
||||
|
||||
exports.createContext = createContext;
|
||||
exports.createNamespace = createNamespace;
|
||||
exports.defaultNamespace = defaultNamespace;
|
||||
exports.executeAsync = executeAsync;
|
||||
exports.getContext = getContext;
|
||||
exports.useContext = useContext;
|
||||
exports.withAsyncContext = withAsyncContext;
|
||||
42
node_modules/unctx/dist/index.d.ts
generated
vendored
Normal file
42
node_modules/unctx/dist/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
interface UseContext<T> {
|
||||
/**
|
||||
* Get the current context. Throws if no context is set.
|
||||
*/
|
||||
use: () => T;
|
||||
/**
|
||||
* Get the current context. Returns `null` when no context is set.
|
||||
*/
|
||||
tryUse: () => T | null;
|
||||
/**
|
||||
* Set the context as Singleton Pattern.
|
||||
*/
|
||||
set: (instance?: T, replace?: Boolean) => void;
|
||||
/**
|
||||
* Clear current context.
|
||||
*/
|
||||
unset: () => void;
|
||||
/**
|
||||
* Exclude a synchronous function with the provided context.
|
||||
*/
|
||||
call: <R>(instance: T, callback: () => R) => R;
|
||||
/**
|
||||
* Exclude an asynchronous function with the provided context.
|
||||
* Requires installing the transform plugin to work properly.
|
||||
*/
|
||||
callAsync: <R>(instance: T, callback: () => R | Promise<R>) => Promise<R>;
|
||||
}
|
||||
declare function createContext<T = any>(): UseContext<T>;
|
||||
interface ContextNamespace {
|
||||
get: <T>(key: string) => UseContext<T>;
|
||||
}
|
||||
declare function createNamespace<T = any>(): {
|
||||
get(key: any): UseContext<T>;
|
||||
};
|
||||
declare const defaultNamespace: ContextNamespace;
|
||||
declare const getContext: <T>(key: string) => UseContext<T>;
|
||||
declare const useContext: <T>(key: string) => () => T;
|
||||
type AsyncFunction<T> = () => Promise<T>;
|
||||
declare function executeAsync<T>(function_: AsyncFunction<T>): [Promise<T>, () => void];
|
||||
declare function withAsyncContext<T = any>(function_: AsyncFunction<T>, transformed?: boolean): AsyncFunction<T>;
|
||||
|
||||
export { ContextNamespace, UseContext, createContext, createNamespace, defaultNamespace, executeAsync, getContext, useContext, withAsyncContext };
|
||||
108
node_modules/unctx/dist/index.mjs
generated
vendored
Normal file
108
node_modules/unctx/dist/index.mjs
generated
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
function createContext() {
|
||||
let currentInstance;
|
||||
let isSingleton = false;
|
||||
const checkConflict = (instance) => {
|
||||
if (currentInstance && currentInstance !== instance) {
|
||||
throw new Error("Context conflict");
|
||||
}
|
||||
};
|
||||
return {
|
||||
use: () => {
|
||||
if (currentInstance === void 0) {
|
||||
throw new Error("Context is not available");
|
||||
}
|
||||
return currentInstance;
|
||||
},
|
||||
tryUse: () => {
|
||||
return currentInstance;
|
||||
},
|
||||
set: (instance, replace) => {
|
||||
if (!replace) {
|
||||
checkConflict(instance);
|
||||
}
|
||||
currentInstance = instance;
|
||||
isSingleton = true;
|
||||
},
|
||||
unset: () => {
|
||||
currentInstance = void 0;
|
||||
isSingleton = false;
|
||||
},
|
||||
call: (instance, callback) => {
|
||||
checkConflict(instance);
|
||||
currentInstance = instance;
|
||||
try {
|
||||
return callback();
|
||||
} finally {
|
||||
if (!isSingleton) {
|
||||
currentInstance = void 0;
|
||||
}
|
||||
}
|
||||
},
|
||||
async callAsync(instance, callback) {
|
||||
currentInstance = instance;
|
||||
const onRestore = () => {
|
||||
currentInstance = instance;
|
||||
};
|
||||
const onLeave = () => currentInstance === instance ? onRestore : void 0;
|
||||
asyncHandlers.add(onLeave);
|
||||
try {
|
||||
const r = callback();
|
||||
if (!isSingleton) {
|
||||
currentInstance = void 0;
|
||||
}
|
||||
return await r;
|
||||
} finally {
|
||||
asyncHandlers.delete(onLeave);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
function createNamespace() {
|
||||
const contexts = {};
|
||||
return {
|
||||
get(key) {
|
||||
if (!contexts[key]) {
|
||||
contexts[key] = createContext();
|
||||
}
|
||||
contexts[key];
|
||||
return contexts[key];
|
||||
}
|
||||
};
|
||||
}
|
||||
const _globalThis = typeof globalThis !== "undefined" ? globalThis : typeof self !== "undefined" ? self : typeof global !== "undefined" ? global : typeof window !== "undefined" ? window : {};
|
||||
const globalKey = "__unctx__";
|
||||
const defaultNamespace = _globalThis[globalKey] || (_globalThis[globalKey] = createNamespace());
|
||||
const getContext = (key) => defaultNamespace.get(key);
|
||||
const useContext = (key) => getContext(key).use;
|
||||
const asyncHandlersKey = "__unctx_async_handlers__";
|
||||
const asyncHandlers = _globalThis[asyncHandlersKey] || (_globalThis[asyncHandlersKey] = /* @__PURE__ */ new Set());
|
||||
function executeAsync(function_) {
|
||||
const restores = [];
|
||||
for (const leaveHandler of asyncHandlers) {
|
||||
const restore2 = leaveHandler();
|
||||
if (restore2) {
|
||||
restores.push(restore2);
|
||||
}
|
||||
}
|
||||
const restore = () => {
|
||||
for (const restore2 of restores) {
|
||||
restore2();
|
||||
}
|
||||
};
|
||||
let awaitable = function_();
|
||||
if (awaitable && typeof awaitable === "object" && "catch" in awaitable) {
|
||||
awaitable = awaitable.catch((error) => {
|
||||
restore();
|
||||
throw error;
|
||||
});
|
||||
}
|
||||
return [awaitable, restore];
|
||||
}
|
||||
function withAsyncContext(function_, transformed) {
|
||||
if (!transformed) {
|
||||
console.warn("[unctx] `withAsyncContext` needs transformation for async context support in", function_, "\n", function_.toString());
|
||||
}
|
||||
return function_;
|
||||
}
|
||||
|
||||
export { createContext, createNamespace, defaultNamespace, executeAsync, getContext, useContext, withAsyncContext };
|
||||
27
node_modules/unctx/dist/plugin.cjs
generated
vendored
Normal file
27
node_modules/unctx/dist/plugin.cjs
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
'use strict';
|
||||
|
||||
const unplugin = require('unplugin');
|
||||
const transform = require('./transform.cjs');
|
||||
require('acorn');
|
||||
require('magic-string');
|
||||
require('estree-walker');
|
||||
|
||||
const unctxPlugin = unplugin.createUnplugin((options = {}) => {
|
||||
const transformer = transform.createTransformer(options);
|
||||
return {
|
||||
name: "unctx:transfrom",
|
||||
enforce: "post",
|
||||
transformInclude: options.transformInclude,
|
||||
transform(code, id) {
|
||||
const result = transformer.transform(code);
|
||||
if (result) {
|
||||
return {
|
||||
code: result.code,
|
||||
map: result.magicString.generateMap({ source: id, includeContent: true })
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
exports.unctxPlugin = unctxPlugin;
|
||||
10
node_modules/unctx/dist/plugin.d.ts
generated
vendored
Normal file
10
node_modules/unctx/dist/plugin.d.ts
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
import * as unplugin from 'unplugin';
|
||||
import { TransformerOptions } from './transform.js';
|
||||
import 'magic-string';
|
||||
|
||||
interface UnctxPluginOptions extends TransformerOptions {
|
||||
transformInclude?: (id: string) => boolean;
|
||||
}
|
||||
declare const unctxPlugin: unplugin.UnpluginInstance<UnctxPluginOptions, false>;
|
||||
|
||||
export { UnctxPluginOptions, unctxPlugin };
|
||||
25
node_modules/unctx/dist/plugin.mjs
generated
vendored
Normal file
25
node_modules/unctx/dist/plugin.mjs
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
import { createUnplugin } from 'unplugin';
|
||||
import { createTransformer } from './transform.mjs';
|
||||
import 'acorn';
|
||||
import 'magic-string';
|
||||
import 'estree-walker';
|
||||
|
||||
const unctxPlugin = createUnplugin((options = {}) => {
|
||||
const transformer = createTransformer(options);
|
||||
return {
|
||||
name: "unctx:transfrom",
|
||||
enforce: "post",
|
||||
transformInclude: options.transformInclude,
|
||||
transform(code, id) {
|
||||
const result = transformer.transform(code);
|
||||
if (result) {
|
||||
return {
|
||||
code: result.code,
|
||||
map: result.magicString.generateMap({ source: id, includeContent: true })
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
export { unctxPlugin };
|
||||
126
node_modules/unctx/dist/transform.cjs
generated
vendored
Normal file
126
node_modules/unctx/dist/transform.cjs
generated
vendored
Normal file
@@ -0,0 +1,126 @@
|
||||
'use strict';
|
||||
|
||||
const acorn = require('acorn');
|
||||
const MagicString = require('magic-string');
|
||||
const estreeWalker = require('estree-walker');
|
||||
|
||||
function _interopNamespaceDefault(e) {
|
||||
const n = Object.create(null);
|
||||
if (e) {
|
||||
for (const k in e) {
|
||||
n[k] = e[k];
|
||||
}
|
||||
}
|
||||
n.default = e;
|
||||
return n;
|
||||
}
|
||||
|
||||
const acorn__namespace = /*#__PURE__*/_interopNamespaceDefault(acorn);
|
||||
|
||||
function createTransformer(options = {}) {
|
||||
options = {
|
||||
asyncFunctions: ["withAsyncContext"],
|
||||
helperModule: "unctx",
|
||||
helperName: "executeAsync",
|
||||
...options
|
||||
};
|
||||
const matchRE = new RegExp(`\\b(${options.asyncFunctions.join("|")})\\(`);
|
||||
function shouldTransform(code) {
|
||||
return typeof code === "string" && matchRE.test(code);
|
||||
}
|
||||
function transform(code, options_ = {}) {
|
||||
if (!options_.force && !shouldTransform(code)) {
|
||||
return;
|
||||
}
|
||||
const ast = acorn__namespace.parse(code, {
|
||||
sourceType: "module",
|
||||
ecmaVersion: "latest",
|
||||
locations: true
|
||||
});
|
||||
const s = new MagicString(code);
|
||||
const lines = code.split("\n");
|
||||
let detected = false;
|
||||
estreeWalker.walk(ast, {
|
||||
enter(node) {
|
||||
if (node.type === "CallExpression") {
|
||||
const functionName = _getFunctionName(node.callee);
|
||||
if (options.asyncFunctions.includes(functionName)) {
|
||||
transformFunctionBody(node);
|
||||
if (functionName !== "callAsync") {
|
||||
const lastArgument = node.arguments[node.arguments.length - 1];
|
||||
if (lastArgument) {
|
||||
s.appendRight(toIndex(lastArgument.loc.end), ",1");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
if (!detected) {
|
||||
return;
|
||||
}
|
||||
s.appendLeft(0, `import { ${options.helperName} as __executeAsync } from "${options.helperModule}";`);
|
||||
return {
|
||||
code: s.toString(),
|
||||
magicString: s
|
||||
};
|
||||
function toIndex(pos) {
|
||||
return lines.slice(0, pos.line - 1).join("\n").length + pos.column + 1;
|
||||
}
|
||||
function transformFunctionBody(node) {
|
||||
for (const function_ of node.arguments) {
|
||||
if (function_.type !== "ArrowFunctionExpression" && function_.type !== "FunctionExpression") {
|
||||
continue;
|
||||
}
|
||||
if (!function_.async) {
|
||||
continue;
|
||||
}
|
||||
const body = function_.body;
|
||||
let injectVariable = false;
|
||||
estreeWalker.walk(body, {
|
||||
enter(node2, parent) {
|
||||
if (node2.type === "AwaitExpression") {
|
||||
detected = true;
|
||||
injectVariable = true;
|
||||
injectForNode(node2, parent);
|
||||
}
|
||||
if (node2.type === "ArrowFunctionExpression" || node2.type === "FunctionExpression" || node2.type === "FunctionDeclaration") {
|
||||
return this.skip();
|
||||
}
|
||||
}
|
||||
});
|
||||
if (injectVariable) {
|
||||
s.appendLeft(
|
||||
toIndex(body.loc.start) + 1,
|
||||
"let __temp, __restore;"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
function injectForNode(node, parent) {
|
||||
const body = code.slice(
|
||||
toIndex(node.argument.loc.start),
|
||||
toIndex(node.argument.loc.end)
|
||||
);
|
||||
const isStatement = parent?.type === "ExpressionStatement";
|
||||
s.overwrite(
|
||||
toIndex(node.loc.start),
|
||||
toIndex(node.loc.end),
|
||||
isStatement ? `;(([__temp,__restore]=__executeAsync(()=>${body})),await __temp,__restore());` : `(([__temp,__restore]=__executeAsync(()=>${body})),__temp=await __temp,__restore(),__temp)`
|
||||
);
|
||||
}
|
||||
}
|
||||
return {
|
||||
transform,
|
||||
shouldTransform
|
||||
};
|
||||
}
|
||||
function _getFunctionName(node) {
|
||||
if (node.type === "Identifier") {
|
||||
return node.name;
|
||||
} else if (node.type === "MemberExpression") {
|
||||
return _getFunctionName(node.property);
|
||||
}
|
||||
}
|
||||
|
||||
exports.createTransformer = createTransformer;
|
||||
29
node_modules/unctx/dist/transform.d.ts
generated
vendored
Normal file
29
node_modules/unctx/dist/transform.d.ts
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
import MagicString from 'magic-string';
|
||||
|
||||
interface TransformerOptions {
|
||||
/**
|
||||
* The function names to be transformed.
|
||||
*
|
||||
* @default ['withAsyncContext', 'callAsync']
|
||||
*/
|
||||
asyncFunctions?: string[];
|
||||
/**
|
||||
* @default 'unctx'
|
||||
*/
|
||||
helperModule?: string;
|
||||
/**
|
||||
* @default 'executeAsync'
|
||||
*/
|
||||
helperName?: string;
|
||||
}
|
||||
declare function createTransformer(options?: TransformerOptions): {
|
||||
transform: (code: string, options_?: {
|
||||
force?: false;
|
||||
}) => {
|
||||
code: string;
|
||||
magicString: MagicString;
|
||||
};
|
||||
shouldTransform: (code: string) => boolean;
|
||||
};
|
||||
|
||||
export { TransformerOptions, createTransformer };
|
||||
111
node_modules/unctx/dist/transform.mjs
generated
vendored
Normal file
111
node_modules/unctx/dist/transform.mjs
generated
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
import * as acorn from 'acorn';
|
||||
import MagicString from 'magic-string';
|
||||
import { walk } from 'estree-walker';
|
||||
|
||||
function createTransformer(options = {}) {
|
||||
options = {
|
||||
asyncFunctions: ["withAsyncContext"],
|
||||
helperModule: "unctx",
|
||||
helperName: "executeAsync",
|
||||
...options
|
||||
};
|
||||
const matchRE = new RegExp(`\\b(${options.asyncFunctions.join("|")})\\(`);
|
||||
function shouldTransform(code) {
|
||||
return typeof code === "string" && matchRE.test(code);
|
||||
}
|
||||
function transform(code, options_ = {}) {
|
||||
if (!options_.force && !shouldTransform(code)) {
|
||||
return;
|
||||
}
|
||||
const ast = acorn.parse(code, {
|
||||
sourceType: "module",
|
||||
ecmaVersion: "latest",
|
||||
locations: true
|
||||
});
|
||||
const s = new MagicString(code);
|
||||
const lines = code.split("\n");
|
||||
let detected = false;
|
||||
walk(ast, {
|
||||
enter(node) {
|
||||
if (node.type === "CallExpression") {
|
||||
const functionName = _getFunctionName(node.callee);
|
||||
if (options.asyncFunctions.includes(functionName)) {
|
||||
transformFunctionBody(node);
|
||||
if (functionName !== "callAsync") {
|
||||
const lastArgument = node.arguments[node.arguments.length - 1];
|
||||
if (lastArgument) {
|
||||
s.appendRight(toIndex(lastArgument.loc.end), ",1");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
if (!detected) {
|
||||
return;
|
||||
}
|
||||
s.appendLeft(0, `import { ${options.helperName} as __executeAsync } from "${options.helperModule}";`);
|
||||
return {
|
||||
code: s.toString(),
|
||||
magicString: s
|
||||
};
|
||||
function toIndex(pos) {
|
||||
return lines.slice(0, pos.line - 1).join("\n").length + pos.column + 1;
|
||||
}
|
||||
function transformFunctionBody(node) {
|
||||
for (const function_ of node.arguments) {
|
||||
if (function_.type !== "ArrowFunctionExpression" && function_.type !== "FunctionExpression") {
|
||||
continue;
|
||||
}
|
||||
if (!function_.async) {
|
||||
continue;
|
||||
}
|
||||
const body = function_.body;
|
||||
let injectVariable = false;
|
||||
walk(body, {
|
||||
enter(node2, parent) {
|
||||
if (node2.type === "AwaitExpression") {
|
||||
detected = true;
|
||||
injectVariable = true;
|
||||
injectForNode(node2, parent);
|
||||
}
|
||||
if (node2.type === "ArrowFunctionExpression" || node2.type === "FunctionExpression" || node2.type === "FunctionDeclaration") {
|
||||
return this.skip();
|
||||
}
|
||||
}
|
||||
});
|
||||
if (injectVariable) {
|
||||
s.appendLeft(
|
||||
toIndex(body.loc.start) + 1,
|
||||
"let __temp, __restore;"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
function injectForNode(node, parent) {
|
||||
const body = code.slice(
|
||||
toIndex(node.argument.loc.start),
|
||||
toIndex(node.argument.loc.end)
|
||||
);
|
||||
const isStatement = parent?.type === "ExpressionStatement";
|
||||
s.overwrite(
|
||||
toIndex(node.loc.start),
|
||||
toIndex(node.loc.end),
|
||||
isStatement ? `;(([__temp,__restore]=__executeAsync(()=>${body})),await __temp,__restore());` : `(([__temp,__restore]=__executeAsync(()=>${body})),__temp=await __temp,__restore(),__temp)`
|
||||
);
|
||||
}
|
||||
}
|
||||
return {
|
||||
transform,
|
||||
shouldTransform
|
||||
};
|
||||
}
|
||||
function _getFunctionName(node) {
|
||||
if (node.type === "Identifier") {
|
||||
return node.name;
|
||||
} else if (node.type === "MemberExpression") {
|
||||
return _getFunctionName(node.property);
|
||||
}
|
||||
}
|
||||
|
||||
export { createTransformer };
|
||||
64
node_modules/unctx/package.json
generated
vendored
Normal file
64
node_modules/unctx/package.json
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
{
|
||||
"name": "unctx",
|
||||
"version": "2.1.1",
|
||||
"description": "Composition-api in Vanilla js",
|
||||
"repository": "unjs/unctx",
|
||||
"license": "MIT",
|
||||
"sideEffects": false,
|
||||
"exports": {
|
||||
".": {
|
||||
"require": "./dist/index.cjs",
|
||||
"import": "./dist/index.mjs",
|
||||
"types": "./dist/index.d.ts"
|
||||
},
|
||||
"./transform": {
|
||||
"import": "./dist/transform.mjs",
|
||||
"types": "./dist/transform.d.ts"
|
||||
},
|
||||
"./plugin": {
|
||||
"import": "./dist/plugin.mjs",
|
||||
"types": "./dist/plugin.d.ts"
|
||||
}
|
||||
},
|
||||
"main": "./dist/index.cjs",
|
||||
"module": "./dist/index.mjs",
|
||||
"types": "./dist/index.d.ts",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
"*": [
|
||||
"./dist/*",
|
||||
"./dist/index.d.ts"
|
||||
]
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"acorn": "^8.8.1",
|
||||
"estree-walker": "^3.0.1",
|
||||
"magic-string": "^0.26.7",
|
||||
"unplugin": "^1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/estree": "^1.0.0",
|
||||
"@types/jest": "^29.2.3",
|
||||
"@types/node": "^18.11.9",
|
||||
"@vitest/coverage-c8": "^0.25.3",
|
||||
"eslint": "^8.28.0",
|
||||
"eslint-config-unjs": "^0.0.2",
|
||||
"jiti": "^1.16.0",
|
||||
"standard-version": "^9.5.0",
|
||||
"typescript": "^4.9.3",
|
||||
"unbuild": "^1.0.1",
|
||||
"vitest": "^0.25.3"
|
||||
},
|
||||
"packageManager": "pnpm@7.17.1",
|
||||
"scripts": {
|
||||
"build": "unbuild",
|
||||
"dev": "vitest",
|
||||
"lint": "eslint --ext .ts,.js .",
|
||||
"release": "pnpm test && standard-version && git push --follow-tags && pnpm publish",
|
||||
"test": "pnpm lint && vitest run --coverage"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user