version 02

This commit is contained in:
Alain Vasquez Ramirez 2025-03-26 19:04:28 -06:00
parent 50469288e1
commit deb60c112f
689 changed files with 17565 additions and 7826 deletions

54
estilo.css Normal file
View File

@ -0,0 +1,54 @@
.footer {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
padding: 10px 15px;
border-top: 1px solid #e6e6e6;
background: white;
font-size: 14px;
}
.todo-count {
flex: 1;
min-width: 100px;
}
.filters {
list-style: none;
display: flex;
flex-wrap: wrap;
gap: 8px;
margin: 0;
padding: 0;
justify-content: center;
flex: 2;
}
.filters li {
display: inline;
}
.filters a {
padding: 3px 7px;
border: 1px solid transparent;
border-radius: 3px;
text-decoration: none;
color: inherit;
}
.filters a.selected {
border-color: rgba(175, 47, 47, 0.2);
}
.clear-completed {
flex: 1;
min-width: 120px;
text-align: right;
background: none;
border: none;
color: #cc9a9a;
cursor: pointer;
text-decoration: underline;
}

View File

@ -12,6 +12,7 @@
<link rel="icon" href="/favicon.ico"> <link rel="icon" href="/favicon.ico">
<link rel="apple-touch-icon" href="/180.png" sizes="180x180"> <link rel="apple-touch-icon" href="/180.png" sizes="180x180">
<title>React Admin ToDo</title> <title>React Admin ToDo</title>
<link rel="stylesheet" href="/estilo.css" />
<meta name="description" content="A ToDo application implemented with React Admin" /> <meta name="description" content="A ToDo application implemented with React Admin" />
</head> </head>

658
node_modules/.package-lock.json generated vendored

File diff suppressed because it is too large Load Diff

View File

@ -1,73 +1,73 @@
{ {
"hash": "c02679aa", "hash": "536f3c70",
"configHash": "475f182c", "configHash": "4b3d8f8b",
"lockfileHash": "07ad5253", "lockfileHash": "0b0e3dce",
"browserHash": "80c74427", "browserHash": "7f27dcc2",
"optimized": { "optimized": {
"react": { "react": {
"src": "../../react/index.js", "src": "../../react/index.js",
"file": "react.js", "file": "react.js",
"fileHash": "f9bb28ca", "fileHash": "8db10fd1",
"needsInterop": true "needsInterop": true
}, },
"react-dom": { "react-dom": {
"src": "../../react-dom/index.js", "src": "../../react-dom/index.js",
"file": "react-dom.js", "file": "react-dom.js",
"fileHash": "6267f293", "fileHash": "5df02561",
"needsInterop": true "needsInterop": true
}, },
"react/jsx-dev-runtime": { "react/jsx-dev-runtime": {
"src": "../../react/jsx-dev-runtime.js", "src": "../../react/jsx-dev-runtime.js",
"file": "react_jsx-dev-runtime.js", "file": "react_jsx-dev-runtime.js",
"fileHash": "761aecf0", "fileHash": "454d74b2",
"needsInterop": true "needsInterop": true
}, },
"react/jsx-runtime": { "react/jsx-runtime": {
"src": "../../react/jsx-runtime.js", "src": "../../react/jsx-runtime.js",
"file": "react_jsx-runtime.js", "file": "react_jsx-runtime.js",
"fileHash": "992e0135", "fileHash": "f9fb0493",
"needsInterop": true "needsInterop": true
}, },
"clsx": { "clsx": {
"src": "../../clsx/dist/clsx.mjs", "src": "../../clsx/dist/clsx.mjs",
"file": "clsx.js", "file": "clsx.js",
"fileHash": "ff4e198a", "fileHash": "0acaaaf7",
"needsInterop": false "needsInterop": false
}, },
"localforage": { "localforage": {
"src": "../../localforage/dist/localforage.js", "src": "../../localforage/dist/localforage.js",
"file": "localforage.js", "file": "localforage.js",
"fileHash": "d190f5b3", "fileHash": "e76b88f1",
"needsInterop": true "needsInterop": true
}, },
"ra-core": { "ra-core": {
"src": "../../ra-core/dist/esm/index.js", "src": "../../ra-core/dist/esm/index.js",
"file": "ra-core.js", "file": "ra-core.js",
"fileHash": "7c2c0698", "fileHash": "6a13df7d",
"needsInterop": false "needsInterop": false
}, },
"ra-data-local-forage": { "ra-data-local-forage": {
"src": "../../ra-data-local-forage/dist/esm/index.js", "src": "../../ra-data-local-forage/dist/esm/index.js",
"file": "ra-data-local-forage.js", "file": "ra-data-local-forage.js",
"fileHash": "ec695e6c", "fileHash": "cd41ed79",
"needsInterop": false "needsInterop": false
}, },
"react-dom/client": { "react-dom/client": {
"src": "../../react-dom/client.js", "src": "../../react-dom/client.js",
"file": "react-dom_client.js", "file": "react-dom_client.js",
"fileHash": "9229e105", "fileHash": "b0b6a4aa",
"needsInterop": true "needsInterop": true
} }
}, },
"chunks": { "chunks": {
"chunk-CPGX2YFR": {
"file": "chunk-CPGX2YFR.js"
},
"chunk-L7VO4W5A": { "chunk-L7VO4W5A": {
"file": "chunk-L7VO4W5A.js" "file": "chunk-L7VO4W5A.js"
}, },
"chunk-FFYJRC36": { "chunk-CPGX2YFR": {
"file": "chunk-FFYJRC36.js" "file": "chunk-CPGX2YFR.js"
},
"chunk-ZPUNMYDO": {
"file": "chunk-ZPUNMYDO.js"
}, },
"chunk-MUYQS5ZK": { "chunk-MUYQS5ZK": {
"file": "chunk-MUYQS5ZK.js" "file": "chunk-MUYQS5ZK.js"

File diff suppressed because one or more lines are too long

View File

@ -2,20 +2,6 @@ import {
__commonJS __commonJS
} from "./chunk-SNAQBZPT.js"; } from "./chunk-SNAQBZPT.js";
// node_modules/lodash/_arrayMap.js
var require_arrayMap = __commonJS({
"node_modules/lodash/_arrayMap.js"(exports, module) {
function arrayMap(array, iteratee) {
var index = -1, length = array == null ? 0 : array.length, result = Array(length);
while (++index < length) {
result[index] = iteratee(array[index], index, array);
}
return result;
}
module.exports = arrayMap;
}
});
// node_modules/lodash/_freeGlobal.js // node_modules/lodash/_freeGlobal.js
var require_freeGlobal = __commonJS({ var require_freeGlobal = __commonJS({
"node_modules/lodash/_freeGlobal.js"(exports, module) { "node_modules/lodash/_freeGlobal.js"(exports, module) {
@ -615,6 +601,34 @@ var require_memoize = __commonJS({
} }
}); });
// node_modules/lodash/_arrayMap.js
var require_arrayMap = __commonJS({
"node_modules/lodash/_arrayMap.js"(exports, module) {
function arrayMap(array, iteratee) {
var index = -1, length = array == null ? 0 : array.length, result = Array(length);
while (++index < length) {
result[index] = iteratee(array[index], index, array);
}
return result;
}
module.exports = arrayMap;
}
});
// node_modules/lodash/_isIndex.js
var require_isIndex = __commonJS({
"node_modules/lodash/_isIndex.js"(exports, module) {
var MAX_SAFE_INTEGER = 9007199254740991;
var reIsUint = /^(?:0|[1-9]\d*)$/;
function isIndex(value, length) {
var type = typeof value;
length = length == null ? MAX_SAFE_INTEGER : length;
return !!length && (type == "number" || type != "symbol" && reIsUint.test(value)) && (value > -1 && value % 1 == 0 && value < length);
}
module.exports = isIndex;
}
});
// node_modules/lodash/isArray.js // node_modules/lodash/isArray.js
var require_isArray = __commonJS({ var require_isArray = __commonJS({
"node_modules/lodash/isArray.js"(exports, module) { "node_modules/lodash/isArray.js"(exports, module) {
@ -806,20 +820,6 @@ var require_get = __commonJS({
} }
}); });
// node_modules/lodash/_isIndex.js
var require_isIndex = __commonJS({
"node_modules/lodash/_isIndex.js"(exports, module) {
var MAX_SAFE_INTEGER = 9007199254740991;
var reIsUint = /^(?:0|[1-9]\d*)$/;
function isIndex(value, length) {
var type = typeof value;
length = length == null ? MAX_SAFE_INTEGER : length;
return !!length && (type == "number" || type != "symbol" && reIsUint.test(value)) && (value > -1 && value % 1 == 0 && value < length);
}
module.exports = isIndex;
}
});
// node_modules/lodash/_arrayPush.js // node_modules/lodash/_arrayPush.js
var require_arrayPush = __commonJS({ var require_arrayPush = __commonJS({
"node_modules/lodash/_arrayPush.js"(exports, module) { "node_modules/lodash/_arrayPush.js"(exports, module) {
@ -1130,36 +1130,36 @@ var require_baseUnset = __commonJS({
}); });
export { export {
require_arrayMap,
require_isArray,
require_freeGlobal, require_freeGlobal,
require_root, require_root,
require_Symbol, require_Symbol,
require_baseGetTag, require_baseGetTag,
require_isObjectLike,
require_isSymbol,
require_isObject, require_isObject,
require_isFunction, require_isFunction,
require_toSource, require_toSource,
require_getNative, require_getNative,
require_defineProperty,
require_eq, require_eq,
require_isArray,
require_isObjectLike,
require_isSymbol,
require_ListCache, require_ListCache,
require_Map, require_Map,
require_MapCache, require_MapCache,
require_memoize, require_memoize,
require_arrayMap,
require_castPath, require_castPath,
require_isIndex,
require_toKey, require_toKey,
require_baseGet, require_baseGet,
require_get,
require_baseUnset, require_baseUnset,
require_isIndex, require_get,
require_arrayPush, require_arrayPush,
require_isArguments, require_isArguments,
require_baseFlatten,
require_overRest,
require_defineProperty,
require_identity, require_identity,
require_overRest,
require_setToString, require_setToString,
require_baseFlatten,
require_flatRest require_flatRest
}; };
//# sourceMappingURL=chunk-FFYJRC36.js.map //# sourceMappingURL=chunk-ZPUNMYDO.js.map

7
node_modules/.vite/deps/chunk-ZPUNMYDO.js.map generated vendored Normal file

File diff suppressed because one or more lines are too long

286
node_modules/.vite/deps/ra-core.js generated vendored
View File

@ -32,7 +32,7 @@ import {
require_setToString, require_setToString,
require_toKey, require_toKey,
require_toSource require_toSource
} from "./chunk-FFYJRC36.js"; } from "./chunk-ZPUNMYDO.js";
import { import {
require_react_dom require_react_dom
} from "./chunk-MUYQS5ZK.js"; } from "./chunk-MUYQS5ZK.js";
@ -3957,9 +3957,9 @@ var require_defaults = __commonJS({
} }
}); });
// node_modules/react-is/cjs/react-is.development.js // node_modules/ra-core/node_modules/react-is/cjs/react-is.development.js
var require_react_is_development = __commonJS({ var require_react_is_development = __commonJS({
"node_modules/react-is/cjs/react-is.development.js"(exports) { "node_modules/ra-core/node_modules/react-is/cjs/react-is.development.js"(exports) {
"use strict"; "use strict";
(function() { (function() {
function typeOf(object) { function typeOf(object) {
@ -4051,9 +4051,9 @@ var require_react_is_development = __commonJS({
} }
}); });
// node_modules/react-is/index.js // node_modules/ra-core/node_modules/react-is/index.js
var require_react_is = __commonJS({ var require_react_is = __commonJS({
"node_modules/react-is/index.js"(exports, module) { "node_modules/ra-core/node_modules/react-is/index.js"(exports, module) {
"use strict"; "use strict";
if (false) { if (false) {
module.exports = null; module.exports = null;
@ -7559,7 +7559,7 @@ function useInfiniteQuery(options, queryClient) {
// node_modules/ra-core/dist/esm/auth/useLogout.js // node_modules/ra-core/dist/esm/auth/useLogout.js
var import_react151 = __toESM(require_react()); var import_react151 = __toESM(require_react());
// node_modules/react-router/dist/development/chunk-HA7DTUK3.mjs // node_modules/react-router/dist/development/chunk-GNGMS2XR.mjs
var React32 = __toESM(require_react(), 1); var React32 = __toESM(require_react(), 1);
var React11 = __toESM(require_react(), 1); var React11 = __toESM(require_react(), 1);
var React22 = __toESM(require_react(), 1); var React22 = __toESM(require_react(), 1);
@ -7570,7 +7570,7 @@ var React42 = __toESM(require_react(), 1);
// node_modules/turbo-stream/dist/turbo-stream.mjs // node_modules/turbo-stream/dist/turbo-stream.mjs
var objectProtoNames = Object.getOwnPropertyNames(Object.prototype).sort().join("\0"); var objectProtoNames = Object.getOwnPropertyNames(Object.prototype).sort().join("\0");
// node_modules/react-router/dist/development/chunk-HA7DTUK3.mjs // node_modules/react-router/dist/development/chunk-GNGMS2XR.mjs
var React82 = __toESM(require_react(), 1); var React82 = __toESM(require_react(), 1);
var React72 = __toESM(require_react(), 1); var React72 = __toESM(require_react(), 1);
var React52 = __toESM(require_react(), 1); var React52 = __toESM(require_react(), 1);
@ -7580,6 +7580,12 @@ var React12 = __toESM(require_react(), 1);
var React13 = __toESM(require_react(), 1); var React13 = __toESM(require_react(), 1);
var import_cookie = __toESM(require_dist(), 1); var import_cookie = __toESM(require_dist(), 1);
var import_set_cookie_parser = __toESM(require_set_cookie(), 1); var import_set_cookie_parser = __toESM(require_set_cookie(), 1);
var __typeError = (msg) => {
throw TypeError(msg);
};
var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
var __privateGet2 = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
var __privateAdd2 = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
var Action = ((Action2) => { var Action = ((Action2) => {
Action2["Pop"] = "POP"; Action2["Pop"] = "POP";
Action2["Push"] = "PUSH"; Action2["Push"] = "PUSH";
@ -7897,6 +7903,30 @@ function getUrlBasedHistory(getLocation, createHref2, validateLocation, options
}; };
return history; return history;
} }
var _map;
var unstable_RouterContextProvider = class {
constructor(init) {
__privateAdd2(this, _map, /* @__PURE__ */ new Map());
if (init) {
for (let [context, value] of init) {
this.set(context, value);
}
}
}
get(context) {
if (__privateGet2(this, _map).has(context)) {
return __privateGet2(this, _map).get(context);
}
if (context.defaultValue !== void 0) {
return context.defaultValue;
}
throw new Error("No value found for context");
}
set(context, value) {
__privateGet2(this, _map).set(context, value);
}
};
_map = /* @__PURE__ */ new WeakMap();
var immutableRouteKeys = /* @__PURE__ */ new Set([ var immutableRouteKeys = /* @__PURE__ */ new Set([
"lazy", "lazy",
"caseSensitive", "caseSensitive",
@ -8391,9 +8421,9 @@ function createRouter(init) {
); );
let inFlightDataRoutes; let inFlightDataRoutes;
let basename = init.basename || "/"; let basename = init.basename || "/";
let dataStrategyImpl = init.dataStrategy || defaultDataStrategy; let dataStrategyImpl = init.dataStrategy || defaultDataStrategyWithMiddleware;
let patchRoutesOnNavigationImpl = init.patchRoutesOnNavigation;
let future = { let future = {
unstable_middleware: false,
...init.future ...init.future
}; };
let unlistenHistory = null; let unlistenHistory = null;
@ -8405,7 +8435,7 @@ function createRouter(init) {
let initialMatches = matchRoutes(dataRoutes, init.history.location, basename); let initialMatches = matchRoutes(dataRoutes, init.history.location, basename);
let initialMatchesIsFOW = false; let initialMatchesIsFOW = false;
let initialErrors = null; let initialErrors = null;
if (initialMatches == null && !patchRoutesOnNavigationImpl) { if (initialMatches == null && !init.patchRoutesOnNavigation) {
let error = getInternalRouterError(404, { let error = getInternalRouterError(404, {
pathname: init.history.location.pathname pathname: init.history.location.pathname
}); });
@ -8837,6 +8867,9 @@ function createRouter(init) {
pendingNavigationController.signal, pendingNavigationController.signal,
opts && opts.submission opts && opts.submission
); );
let scopedContext = new unstable_RouterContextProvider(
init.unstable_getContext ? await init.unstable_getContext() : void 0
);
let pendingActionResult; let pendingActionResult;
if (opts && opts.pendingError) { if (opts && opts.pendingError) {
pendingActionResult = [ pendingActionResult = [
@ -8849,6 +8882,7 @@ function createRouter(init) {
location, location,
opts.submission, opts.submission,
matches, matches,
scopedContext,
fogOfWar.active, fogOfWar.active,
{ replace: opts.replace, flushSync: flushSync2 } { replace: opts.replace, flushSync: flushSync2 }
); );
@ -8889,6 +8923,7 @@ function createRouter(init) {
request, request,
location, location,
matches, matches,
scopedContext,
fogOfWar.active, fogOfWar.active,
loadingNavigation, loadingNavigation,
opts && opts.submission, opts && opts.submission,
@ -8909,7 +8944,7 @@ function createRouter(init) {
errors errors
}); });
} }
async function handleAction(request, location, submission, matches, isFogOfWar, opts = {}) { async function handleAction(request, location, submission, matches, scopedContext, isFogOfWar, opts = {}) {
interruptActiveLoads(); interruptActiveLoads();
let navigation = getSubmittingNavigation(location, submission); let navigation = getSubmittingNavigation(location, submission);
updateState({ navigation }, { flushSync: opts.flushSync === true }); updateState({ navigation }, { flushSync: opts.flushSync === true });
@ -8965,13 +9000,21 @@ function createRouter(init) {
} else { } else {
let results = await callDataStrategy( let results = await callDataStrategy(
"action", "action",
state,
request, request,
[actionMatch], [actionMatch],
matches, matches,
scopedContext,
null null
); );
result = results[actionMatch.route.id]; result = results[actionMatch.route.id];
if (!result) {
for (let match2 of matches) {
if (results[match2.route.id]) {
result = results[match2.route.id];
break;
}
}
}
if (request.signal.aborted) { if (request.signal.aborted) {
return { shortCircuited: true }; return { shortCircuited: true };
} }
@ -9009,7 +9052,7 @@ function createRouter(init) {
pendingActionResult: [actionMatch.route.id, result] pendingActionResult: [actionMatch.route.id, result]
}; };
} }
async function handleLoaders(request, location, matches, isFogOfWar, overrideNavigation, submission, fetcherSubmission, replace2, initialHydration, flushSync2, pendingActionResult) { async function handleLoaders(request, location, matches, scopedContext, isFogOfWar, overrideNavigation, submission, fetcherSubmission, replace2, initialHydration, flushSync2, pendingActionResult) {
let loadingNavigation = overrideNavigation || getLoadingNavigation(location, submission); let loadingNavigation = overrideNavigation || getLoadingNavigation(location, submission);
let activeSubmission = submission || fetcherSubmission || getSubmissionFromNavigation(loadingNavigation); let activeSubmission = submission || fetcherSubmission || getSubmissionFromNavigation(loadingNavigation);
let shouldUpdateNavigationState = !isUninterruptedRevalidation && !initialHydration; let shouldUpdateNavigationState = !isUninterruptedRevalidation && !initialHydration;
@ -9119,11 +9162,11 @@ function createRouter(init) {
); );
} }
let { loaderResults, fetcherResults } = await callLoadersAndMaybeResolveData( let { loaderResults, fetcherResults } = await callLoadersAndMaybeResolveData(
state,
matches, matches,
matchesToLoad, matchesToLoad,
revalidatingFetchers, revalidatingFetchers,
request request,
scopedContext
); );
if (request.signal.aborted) { if (request.signal.aborted) {
return { shortCircuited: true }; return { shortCircuited: true };
@ -9231,6 +9274,9 @@ function createRouter(init) {
return; return;
} }
let match2 = getTargetMatch(matches, path); let match2 = getTargetMatch(matches, path);
let scopedContext = new unstable_RouterContextProvider(
init.unstable_getContext ? await init.unstable_getContext() : void 0
);
let preventScrollReset = (opts && opts.preventScrollReset) === true; let preventScrollReset = (opts && opts.preventScrollReset) === true;
if (submission && isMutationMethod(submission.formMethod)) { if (submission && isMutationMethod(submission.formMethod)) {
await handleFetcherAction( await handleFetcherAction(
@ -9239,6 +9285,7 @@ function createRouter(init) {
path, path,
match2, match2,
matches, matches,
scopedContext,
fogOfWar.active, fogOfWar.active,
flushSync2, flushSync2,
preventScrollReset, preventScrollReset,
@ -9253,13 +9300,14 @@ function createRouter(init) {
path, path,
match2, match2,
matches, matches,
scopedContext,
fogOfWar.active, fogOfWar.active,
flushSync2, flushSync2,
preventScrollReset, preventScrollReset,
submission submission
); );
} }
async function handleFetcherAction(key, routeId, path, match2, requestMatches, isFogOfWar, flushSync2, preventScrollReset, submission) { async function handleFetcherAction(key, routeId, path, match2, requestMatches, scopedContext, isFogOfWar, flushSync2, preventScrollReset, submission) {
interruptActiveLoads(); interruptActiveLoads();
fetchLoadMatches.delete(key); fetchLoadMatches.delete(key);
function detectAndHandle405Error(m) { function detectAndHandle405Error(m) {
@ -9292,7 +9340,8 @@ function createRouter(init) {
let discoverResult = await discoverRoutes( let discoverResult = await discoverRoutes(
requestMatches, requestMatches,
path, path,
fetchRequest.signal fetchRequest.signal,
key
); );
if (discoverResult.type === "aborted") { if (discoverResult.type === "aborted") {
return; return;
@ -9319,10 +9368,10 @@ function createRouter(init) {
let originatingLoadId = incrementingLoadId; let originatingLoadId = incrementingLoadId;
let actionResults = await callDataStrategy( let actionResults = await callDataStrategy(
"action", "action",
state,
fetchRequest, fetchRequest,
[match2], [match2],
requestMatches, requestMatches,
scopedContext,
key key
); );
let actionResult = actionResults[match2.route.id]; let actionResult = actionResults[match2.route.id];
@ -9406,11 +9455,11 @@ function createRouter(init) {
abortPendingFetchRevalidations abortPendingFetchRevalidations
); );
let { loaderResults, fetcherResults } = await callLoadersAndMaybeResolveData( let { loaderResults, fetcherResults } = await callLoadersAndMaybeResolveData(
state,
matches, matches,
matchesToLoad, matchesToLoad,
revalidatingFetchers, revalidatingFetchers,
revalidationRequest revalidationRequest,
scopedContext
); );
if (abortController.signal.aborted) { if (abortController.signal.aborted) {
return; return;
@ -9477,7 +9526,7 @@ function createRouter(init) {
isRevalidationRequired = false; isRevalidationRequired = false;
} }
} }
async function handleFetcherLoader(key, routeId, path, match2, matches, isFogOfWar, flushSync2, preventScrollReset, submission) { async function handleFetcherLoader(key, routeId, path, match2, matches, scopedContext, isFogOfWar, flushSync2, preventScrollReset, submission) {
let existingFetcher = state.fetchers.get(key); let existingFetcher = state.fetchers.get(key);
updateFetcherState( updateFetcherState(
key, key,
@ -9497,7 +9546,8 @@ function createRouter(init) {
let discoverResult = await discoverRoutes( let discoverResult = await discoverRoutes(
matches, matches,
path, path,
fetchRequest.signal fetchRequest.signal,
key
); );
if (discoverResult.type === "aborted") { if (discoverResult.type === "aborted") {
return; return;
@ -9521,10 +9571,10 @@ function createRouter(init) {
let originatingLoadId = incrementingLoadId; let originatingLoadId = incrementingLoadId;
let results = await callDataStrategy( let results = await callDataStrategy(
"loader", "loader",
state,
fetchRequest, fetchRequest,
[match2], [match2],
matches, matches,
scopedContext,
key key
); );
let result = results[match2.route.id]; let result = results[match2.route.id];
@ -9626,20 +9676,21 @@ function createRouter(init) {
}); });
} }
} }
async function callDataStrategy(type, state2, request, matchesToLoad, matches, fetcherKey) { async function callDataStrategy(type, request, matchesToLoad, matches, scopedContext, fetcherKey) {
let results; let results;
let dataResults = {}; let dataResults = {};
try { try {
results = await callDataStrategyImpl( results = await callDataStrategyImpl(
dataStrategyImpl, dataStrategyImpl,
type, type,
state2,
request, request,
matchesToLoad, matchesToLoad,
matches, matches,
fetcherKey, fetcherKey,
manifest, manifest,
mapRouteProperties2 mapRouteProperties2,
scopedContext,
future.unstable_middleware
); );
} catch (e) { } catch (e) {
matchesToLoad.forEach((m) => { matchesToLoad.forEach((m) => {
@ -9671,13 +9722,13 @@ function createRouter(init) {
} }
return dataResults; return dataResults;
} }
async function callLoadersAndMaybeResolveData(state2, matches, matchesToLoad, fetchersToLoad, request) { async function callLoadersAndMaybeResolveData(matches, matchesToLoad, fetchersToLoad, request, scopedContext) {
let loaderResultsPromise = callDataStrategy( let loaderResultsPromise = callDataStrategy(
"loader", "loader",
state2,
request, request,
matchesToLoad, matchesToLoad,
matches, matches,
scopedContext,
null null
); );
let fetcherResultsPromise = Promise.all( let fetcherResultsPromise = Promise.all(
@ -9685,10 +9736,10 @@ function createRouter(init) {
if (f.matches && f.match && f.controller) { if (f.matches && f.match && f.controller) {
let results = await callDataStrategy( let results = await callDataStrategy(
"loader", "loader",
state2,
createClientSideRequest(init.history, f.path, f.controller.signal), createClientSideRequest(init.history, f.path, f.controller.signal),
[f.match], [f.match],
f.matches, f.matches,
scopedContext,
f.key f.key
); );
let result = results[f.match.route.id]; let result = results[f.match.route.id];
@ -9910,7 +9961,7 @@ function createRouter(init) {
return null; return null;
} }
function checkFogOfWar(matches, routesToUse, pathname) { function checkFogOfWar(matches, routesToUse, pathname) {
if (patchRoutesOnNavigationImpl) { if (init.patchRoutesOnNavigation) {
if (!matches) { if (!matches) {
let fogMatches = matchRoutesImpl( let fogMatches = matchRoutesImpl(
routesToUse, routesToUse,
@ -9933,8 +9984,8 @@ function createRouter(init) {
} }
return { active: false, matches: null }; return { active: false, matches: null };
} }
async function discoverRoutes(matches, pathname, signal) { async function discoverRoutes(matches, pathname, signal, fetcherKey) {
if (!patchRoutesOnNavigationImpl) { if (!init.patchRoutesOnNavigation) {
return { type: "success", matches }; return { type: "success", matches };
} }
let partialMatches = matches; let partialMatches = matches;
@ -9943,10 +9994,11 @@ function createRouter(init) {
let routesToUse = inFlightDataRoutes || dataRoutes; let routesToUse = inFlightDataRoutes || dataRoutes;
let localManifest = manifest; let localManifest = manifest;
try { try {
await patchRoutesOnNavigationImpl({ await init.patchRoutesOnNavigation({
signal, signal,
path: pathname, path: pathname,
matches: partialMatches, matches: partialMatches,
fetcherKey,
patch: (routeId, children) => { patch: (routeId, children) => {
if (signal.aborted) return; if (signal.aborted) return;
patchRoutesImpl( patchRoutesImpl(
@ -10434,20 +10486,127 @@ async function loadLazyRouteModule(route, mapRouteProperties2, manifest) {
lazy: void 0 lazy: void 0
}); });
} }
async function defaultDataStrategy({ async function defaultDataStrategy(args) {
matches let matchesToLoad = args.matches.filter((m) => m.shouldLoad);
}) { let keyedResults = {};
let matchesToLoad = matches.filter((m) => m.shouldLoad);
let results = await Promise.all(matchesToLoad.map((m) => m.resolve())); let results = await Promise.all(matchesToLoad.map((m) => m.resolve()));
return results.reduce( results.forEach((result, i) => {
(acc, result, i) => Object.assign(acc, { [matchesToLoad[i].route.id]: result }), keyedResults[matchesToLoad[i].route.id] = result;
{} });
return keyedResults;
}
async function defaultDataStrategyWithMiddleware(args) {
if (!args.matches.some((m) => m.route.unstable_middleware)) {
return defaultDataStrategy(args);
}
return runMiddlewarePipeline(
args,
false,
() => defaultDataStrategy(args),
(error, routeId) => ({ [routeId]: { type: "error", result: error } })
); );
} }
async function callDataStrategyImpl(dataStrategyImpl, type, state, request, matchesToLoad, matches, fetcherKey, manifest, mapRouteProperties2, requestContext) { async function runMiddlewarePipeline(args, propagateResult, handler, errorHandler) {
let { matches, request, params, context } = args;
let middlewareState = {
handlerResult: void 0
};
try {
let tuples = matches.flatMap(
(m) => m.route.unstable_middleware ? m.route.unstable_middleware.map((fn) => [m.route.id, fn]) : []
);
let result = await callRouteMiddleware(
{ request, params, context },
tuples,
propagateResult,
middlewareState,
handler
);
return propagateResult ? result : middlewareState.handlerResult;
} catch (e) {
if (!middlewareState.middlewareError) {
throw e;
}
let result = await errorHandler(
middlewareState.middlewareError.error,
middlewareState.middlewareError.routeId
);
if (propagateResult || !middlewareState.handlerResult) {
return result;
}
return Object.assign(middlewareState.handlerResult, result);
}
}
async function callRouteMiddleware(args, middlewares, propagateResult, middlewareState, handler, idx = 0) {
let { request } = args;
if (request.signal.aborted) {
if (request.signal.reason) {
throw request.signal.reason;
}
throw new Error(
`Request aborted without an \`AbortSignal.reason\`: ${request.method} ${request.url}`
);
}
let tuple = middlewares[idx];
if (!tuple) {
middlewareState.handlerResult = await handler();
return middlewareState.handlerResult;
}
let [routeId, middleware] = tuple;
let nextCalled = false;
let nextResult = void 0;
let next = async () => {
if (nextCalled) {
throw new Error("You may only call `next()` once per middleware");
}
nextCalled = true;
let result = await callRouteMiddleware(
args,
middlewares,
propagateResult,
middlewareState,
handler,
idx + 1
);
if (propagateResult) {
nextResult = result;
return nextResult;
}
};
try {
let result = await middleware(
{
request: args.request,
params: args.params,
context: args.context
},
next
);
if (nextCalled) {
if (result === void 0) {
return nextResult;
} else {
return result;
}
} else {
return next();
}
} catch (error) {
if (!middlewareState.middlewareError) {
middlewareState.middlewareError = { routeId, error };
} else if (middlewareState.middlewareError.error !== error) {
middlewareState.middlewareError = { routeId, error };
}
throw error;
}
}
async function callDataStrategyImpl(dataStrategyImpl, type, request, matchesToLoad, matches, fetcherKey, manifest, mapRouteProperties2, scopedContext, enableMiddleware) {
let loadRouteDefinitionsPromises = matches.map( let loadRouteDefinitionsPromises = matches.map(
(m) => m.route.lazy ? loadLazyRouteModule(m.route, mapRouteProperties2, manifest) : void 0 (m) => m.route.lazy ? loadLazyRouteModule(m.route, mapRouteProperties2, manifest) : void 0
); );
if (enableMiddleware) {
await Promise.all(loadRouteDefinitionsPromises);
}
let dsMatches = matches.map((match2, i) => { let dsMatches = matches.map((match2, i) => {
let loadRoutePromise = loadRouteDefinitionsPromises[i]; let loadRoutePromise = loadRouteDefinitionsPromises[i];
let shouldLoad = matchesToLoad.some((m) => m.route.id === match2.route.id); let shouldLoad = matchesToLoad.some((m) => m.route.id === match2.route.id);
@ -10461,7 +10620,7 @@ async function callDataStrategyImpl(dataStrategyImpl, type, state, request, matc
match2, match2,
loadRoutePromise, loadRoutePromise,
handlerOverride, handlerOverride,
requestContext scopedContext
) : Promise.resolve({ type: "data", result: void 0 }); ) : Promise.resolve({ type: "data", result: void 0 });
}; };
return { return {
@ -10475,7 +10634,7 @@ async function callDataStrategyImpl(dataStrategyImpl, type, state, request, matc
request, request,
params: matches[0].params, params: matches[0].params,
fetcherKey, fetcherKey,
context: requestContext context: scopedContext
}); });
try { try {
await Promise.all(loadRouteDefinitionsPromises); await Promise.all(loadRouteDefinitionsPromises);
@ -10483,7 +10642,7 @@ async function callDataStrategyImpl(dataStrategyImpl, type, state, request, matc
} }
return results; return results;
} }
async function callLoaderOrAction(type, request, match2, loadRoutePromise, handlerOverride, staticContext) { async function callLoaderOrAction(type, request, match2, loadRoutePromise, handlerOverride, scopedContext) {
let result; let result;
let onReject; let onReject;
let runHandler = (handler) => { let runHandler = (handler) => {
@ -10503,7 +10662,7 @@ async function callLoaderOrAction(type, request, match2, loadRoutePromise, handl
{ {
request, request,
params: match2.params, params: match2.params,
context: staticContext context: scopedContext
}, },
...ctx !== void 0 ? [ctx] : [] ...ctx !== void 0 ? [ctx] : []
); );
@ -11762,6 +11921,7 @@ function mapRouteProperties(route) {
function createMemoryRouter(routes, opts) { function createMemoryRouter(routes, opts) {
return createRouter({ return createRouter({
basename: opts == null ? void 0 : opts.basename, basename: opts == null ? void 0 : opts.basename,
unstable_getContext: opts == null ? void 0 : opts.unstable_getContext,
future: opts == null ? void 0 : opts.future, future: opts == null ? void 0 : opts.future,
history: createMemoryHistory({ history: createMemoryHistory({
initialEntries: opts == null ? void 0 : opts.initialEntries, initialEntries: opts == null ? void 0 : opts.initialEntries,
@ -12383,7 +12543,7 @@ function dedupeLinkDescriptors(descriptors, preloads) {
}, []); }, []);
} }
var SingleFetchRedirectSymbol = Symbol("SingleFetchRedirect"); var SingleFetchRedirectSymbol = Symbol("SingleFetchRedirect");
function singleFetchUrl(reqUrl) { function singleFetchUrl(reqUrl, basename) {
let url = typeof reqUrl === "string" ? new URL( let url = typeof reqUrl === "string" ? new URL(
reqUrl, reqUrl,
// This can be called during the SSR flow via PrefetchPageLinksImpl so // This can be called during the SSR flow via PrefetchPageLinksImpl so
@ -12392,6 +12552,8 @@ function singleFetchUrl(reqUrl) {
) : reqUrl; ) : reqUrl;
if (url.pathname === "/") { if (url.pathname === "/") {
url.pathname = "_root.data"; url.pathname = "_root.data";
} else if (basename && stripBasename(url.pathname, basename) === "/") {
url.pathname = `${basename.replace(/\/$/, "")}/_root.data`;
} else { } else {
url.pathname = `${url.pathname.replace(/\/$/, "")}.data`; url.pathname = `${url.pathname.replace(/\/$/, "")}.data`;
} }
@ -12528,6 +12690,7 @@ function PrefetchPageLinksImpl({
}) { }) {
let location = useLocation(); let location = useLocation();
let { manifest, routeModules } = useFrameworkContext(); let { manifest, routeModules } = useFrameworkContext();
let { basename } = useDataRouterContext2();
let { loaderData, matches } = useDataRouterStateContext(); let { loaderData, matches } = useDataRouterStateContext();
let newMatchesForData = React92.useMemo( let newMatchesForData = React92.useMemo(
() => getNewMatchesForLinks( () => getNewMatchesForLinks(
@ -12574,7 +12737,7 @@ function PrefetchPageLinksImpl({
if (routesParams.size === 0) { if (routesParams.size === 0) {
return []; return [];
} }
let url = singleFetchUrl(page); let url = singleFetchUrl(page, basename);
if (foundOptOutRoute && routesParams.size > 0) { if (foundOptOutRoute && routesParams.size > 0) {
url.searchParams.set( url.searchParams.set(
"_routes", "_routes",
@ -12583,6 +12746,7 @@ function PrefetchPageLinksImpl({
} }
return [url.pathname + url.search]; return [url.pathname + url.search];
}, [ }, [
basename,
loaderData, loaderData,
location, location,
manifest, manifest,
@ -12616,13 +12780,14 @@ function mergeRefs(...refs) {
var isBrowser = typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.document.createElement !== "undefined"; var isBrowser = typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.document.createElement !== "undefined";
try { try {
if (isBrowser) { if (isBrowser) {
window.__reactRouterVersion = "7.2.0"; window.__reactRouterVersion = "7.4.0";
} }
} catch (e) { } catch (e) {
} }
function createHashRouter(routes, opts) { function createHashRouter(routes, opts) {
return createRouter({ return createRouter({
basename: opts == null ? void 0 : opts.basename, basename: opts == null ? void 0 : opts.basename,
unstable_getContext: opts == null ? void 0 : opts.unstable_getContext,
future: opts == null ? void 0 : opts.future, future: opts == null ? void 0 : opts.future,
history: createHashHistory({ window: opts == null ? void 0 : opts.window }), history: createHashHistory({ window: opts == null ? void 0 : opts.window }),
hydrationData: (opts == null ? void 0 : opts.hydrationData) || parseHydrationData(), hydrationData: (opts == null ? void 0 : opts.hydrationData) || parseHydrationData(),
@ -14604,6 +14769,7 @@ var useRedirect = function() {
var basename = useBasename(); var basename = useBasename();
var createPath2 = useCreatePath(); var createPath2 = useCreatePath();
return (0, import_react34.useCallback)(function(redirectTo, resource, id, data2, state) { return (0, import_react34.useCallback)(function(redirectTo, resource, id, data2, state) {
var _a11;
if (resource === void 0) { if (resource === void 0) {
resource = ""; resource = "";
} }
@ -14614,7 +14780,7 @@ var useRedirect = function() {
return; return;
} else if (typeof redirectTo === "function") { } else if (typeof redirectTo === "function") {
var target = redirectTo(resource, id, data2); var target = redirectTo(resource, id, data2);
var absoluteTarget = typeof target === "string" ? "".concat(basename, "/").concat(target) : __assign3({ pathname: "".concat(basename, "/").concat(target.pathname) }, target); var absoluteTarget = typeof target === "string" ? "".concat(basename).concat(target.startsWith("/") ? "" : "/").concat(target) : __assign3({ pathname: "".concat(basename).concat(((_a11 = target.pathname) === null || _a11 === void 0 ? void 0 : _a11.startsWith("/")) ? "" : "/").concat(target.pathname) }, target);
navigate(absoluteTarget, { navigate(absoluteTarget, {
state: __assign3({ _scrollToTop: true }, state) state: __assign3({ _scrollToTop: true }, state)
}); });
@ -19222,7 +19388,17 @@ var useListController = function(props) {
_: error2 === null || error2 === void 0 ? void 0 : error2.message _: error2 === null || error2 === void 0 ? void 0 : error2.message
} }
}); });
} }, otherQueryOptions)), data2 = _k.data, pageInfo = _k.pageInfo, total = _k.total, responseMeta = _k.meta, error = _k.error, isLoading = _k.isLoading, isFetching = _k.isFetching, isPending = _k.isPending, refetch2 = _k.refetch; } }, otherQueryOptions)), data2 = _k.data, pageInfo = _k.pageInfo, total = _k.total, responseMeta = _k.meta, error = _k.error, isLoading = _k.isLoading, isFetching = _k.isFetching, isPending = _k.isPending, refetch2 = _k.refetch, isPaused = _k.isPaused, isPlaceholderData = _k.isPlaceholderData;
(0, import_react76.useEffect)(function() {
if (isPaused && isPlaceholderData) {
notify("ra.message.placeholder_data_warning", {
type: "warning",
messageArgs: {
_: "Network issue: Data refresh failed."
}
});
}
}, [isPaused, isPlaceholderData, notify]);
(0, import_react76.useEffect)(function() { (0, import_react76.useEffect)(function() {
if (query.page <= 0 || !isFetching && query.page > 1 && (data2 == null || (data2 === null || data2 === void 0 ? void 0 : data2.length) === 0)) { if (query.page <= 0 || !isFetching && query.page > 1 && (data2 == null || (data2 === null || data2 === void 0 ? void 0 : data2.length) === 0)) {
queryModifiers.setPage(1); queryModifiers.setPage(1);
@ -33117,9 +33293,9 @@ inflection/lib/inflection.js:
* A port of inflection-js to node.js module. * A port of inflection-js to node.js module.
*) *)
react-router/dist/development/chunk-HA7DTUK3.mjs: react-router/dist/development/chunk-GNGMS2XR.mjs:
(** (**
* react-router v7.2.0 * react-router v7.4.0
* *
* Copyright (c) Remix Software Inc. * Copyright (c) Remix Software Inc.
* *
@ -33131,7 +33307,7 @@ react-router/dist/development/chunk-HA7DTUK3.mjs:
react-router/dist/development/dom-export.mjs: react-router/dist/development/dom-export.mjs:
(** (**
* react-router v7.2.0 * react-router v7.4.0
* *
* Copyright (c) Remix Software Inc. * Copyright (c) Remix Software Inc.
* *
@ -33143,7 +33319,7 @@ react-router/dist/development/dom-export.mjs:
react-router/dist/development/index.mjs: react-router/dist/development/index.mjs:
(** (**
* react-router v7.2.0 * react-router v7.4.0
* *
* Copyright (c) Remix Software Inc. * Copyright (c) Remix Software Inc.
* *
@ -33155,7 +33331,7 @@ react-router/dist/development/index.mjs:
react-router-dom/dist/index.mjs: react-router-dom/dist/index.mjs:
(** (**
* react-router-dom v7.2.0 * react-router-dom v7.4.0
* *
* Copyright (c) Remix Software Inc. * Copyright (c) Remix Software Inc.
* *

File diff suppressed because one or more lines are too long

View File

@ -8,7 +8,7 @@ import {
require_get, require_get,
require_isIndex, require_isIndex,
require_isSymbol require_isSymbol
} from "./chunk-FFYJRC36.js"; } from "./chunk-ZPUNMYDO.js";
import { import {
__commonJS, __commonJS,
__toESM __toESM

View File

@ -15,7 +15,7 @@ npm i @asamuzakjp/css-color
## Usage ## Usage
```javascript ```javascript
import { convert, isColor, resolve } from '@asamuzakjp/css-color'; import { convert, resolve, utils } from '@asamuzakjp/css-color';
const resolvedValue = resolve( const resolvedValue = resolve(
'color-mix(in oklab, lch(67.5345 42.5 258.2), color(srgb 0 0.5 0))' 'color-mix(in oklab, lch(67.5345 42.5 258.2), color(srgb 0 0.5 0))'
@ -25,7 +25,7 @@ const resolvedValue = resolve(
const convertedValue = covert.colorToHex('lab(46.2775% -47.5621 48.5837)'); const convertedValue = covert.colorToHex('lab(46.2775% -47.5621 48.5837)');
// '#008000' // '#008000'
const result = isColor('green'); const result = utils.isColor('green');
// true // true
``` ```
@ -38,9 +38,7 @@ resolves CSS color
#### Parameters #### Parameters
- `color` **[string][133]** color value - `color` **[string][133]** color value
- system colors are not supported - system colors are not supported
- `opt` **[object][135]?** options (optional, default `{}`) - `opt` **[object][135]?** options (optional, default `{}`)
- `opt.currentColor` **[string][133]?** - `opt.currentColor` **[string][133]?**
- color to use for `currentcolor` keyword - color to use for `currentcolor` keyword
@ -86,7 +84,7 @@ resolves CSS color
```javascript ```javascript
const opt = { const opt = {
dimension: { dimension: {
callback: (unit) => { callback: unit => {
switch (unit) { switch (unit) {
case 'em': case 'em':
return 12; return 12;
@ -107,10 +105,8 @@ resolves CSS color
- `specifiedValue`, [specified value][140] of the color - `specifiedValue`, [specified value][140] of the color
- `hex`, hex color notation, i.e. `#rrggbb` - `hex`, hex color notation, i.e. `#rrggbb`
- `hexAlpha`, hex color notation with alpha channel, i.e. `#rrggbbaa` - `hexAlpha`, hex color notation with alpha channel, i.e. `#rrggbbaa`
- `opt.key` **any?**
- key to return with the value, e.g. CSS property `background-color`
Returns **([string][133]? | [Array][137])** one of `rgba?()`, `#rrggbb(aa)?`, `color-name`, `color(color-space r g b / alpha)`, `color(color-space x y z / alpha)`, `(ok)?lab(l a b / alpha)`, `(ok)?lch(l c h / alpha)`, `'(empty-string)'`, `null`, or `[key, rgba?()]` etc. if `key` is specified Returns **[string][133]?** one of `rgba?()`, `#rrggbb(aa)?`, `color-name`, `color(color-space r g b / alpha)`, `color(color-space x y z / alpha)`, `(ok)?lab(l a b / alpha)`, `(ok)?lch(l c h / alpha)`, `'(empty-string)'`, `null`
- in `computedValue`, values are numbers, however `rgb()` values are integers - in `computedValue`, values are numbers, however `rgb()` values are integers
- in `specifiedValue`, returns `empty string` for unknown and/or invalid color - in `specifiedValue`, returns `empty string` for unknown and/or invalid color
@ -283,7 +279,11 @@ convert color to xyz-d50
Returns **[Array][137]<[number][134]>** \[x, y, z, alpha] Returns **[Array][137]<[number][134]>** \[x, y, z, alpha]
### isColor(color) ### utils
Contains utility functions.
### utils.isColor(color)
is valid color type is valid color type

View File

@ -15,11 +15,10 @@
"dist", "dist",
"src" "src"
], ],
"packageManager": "pnpm@9.15.3",
"type": "module", "type": "module",
"types": "dist/esm/index.d.ts", "types": "dist/esm/index.d.ts",
"main": "dist/cjs/index.cjs",
"module": "dist/esm/index.js", "module": "dist/esm/index.js",
"main": "dist/cjs/index.cjs",
"exports": { "exports": {
".": { ".": {
"import": { "import": {
@ -33,40 +32,45 @@
}, },
"./package.json": "./package.json" "./package.json": "./package.json"
}, },
"packageManager": "pnpm@10.6.1",
"dependencies": { "dependencies": {
"@csstools/css-calc": "^2.1.1", "@csstools/css-calc": "^2.1.2",
"@csstools/css-color-parser": "^3.0.7", "@csstools/css-color-parser": "^3.0.8",
"@csstools/css-parser-algorithms": "^3.0.4", "@csstools/css-parser-algorithms": "^3.0.4",
"@csstools/css-tokenizer": "^3.0.3", "@csstools/css-tokenizer": "^3.0.3",
"lru-cache": "^10.4.3" "lru-cache": "^10.4.3"
}, },
"devDependencies": { "devDependencies": {
"@tanstack/config": "^0.15.1", "@tanstack/vite-config": "^0.1.0",
"@vitest/coverage-istanbul": "^2.1.8", "@vitest/coverage-istanbul": "^3.0.8",
"esbuild": "^0.24.2", "esbuild": "^0.25.0",
"eslint": "^9.18.0", "eslint": "^9.22.0",
"knip": "^5.42.0", "eslint-plugin-import-x": "^4.6.1",
"neostandard": "^0.12.0", "eslint-plugin-regexp": "^2.7.0",
"prettier": "^3.4.2", "globals": "^16.0.0",
"publint": "^0.3.2", "knip": "^5.45.0",
"neostandard": "^0.12.1",
"prettier": "^3.5.3",
"publint": "^0.3.8",
"rimraf": "^6.0.1", "rimraf": "^6.0.1",
"typescript": "^5.7.3", "tsup": "^8.4.0",
"vite": "^6.0.7", "typescript": "^5.8.2",
"vitest": "^2.1.8" "vite": "^6.2.1",
"vitest": "^3.0.8"
}, },
"scripts": { "scripts": {
"build": "pnpm run build:rest && pnpm run build:min", "build": "pnpm run clean && pnpm run test && pnpm run knip && pnpm run build:prod && pnpm run build:cjs && pnpm run build:browser && pnpm run publint",
"build:min": "vite build -c vite.browser.config.ts", "build:browser": "vite build -c ./vite.browser.config.ts",
"build:rest": "vite build", "build:prod": "vite build",
"clean": "rimraf ./dist && rimraf ./coverage", "build:cjs": "tsup ./src/index.ts --format=cjs --platform=node --outDir=./dist/cjs/ --sourcemap --dts",
"prettier": "prettier --ignore-unknown .", "clean": "rimraf ./coverage ./dist",
"prettier:write": "pnpm run prettier --write", "knip": "knip",
"test": "pnpm run \"/^test:.*/\" && pnpm run build && pnpm run publint", "prettier": "prettier . --ignore-unknown --write",
"publint": "publint --strict", "publint": "publint --strict",
"test:lib": "vitest", "test": "pnpm run prettier && pnpm run --stream \"/^test:.*/\"",
"test:eslint": "eslint ./src ./tests", "test:eslint": "eslint ./src ./test --fix",
"test:knip": "knip", "test:types": "tsc",
"test:types": "tsc" "test:unit": "vitest"
}, },
"version": "2.8.3" "version": "3.1.1"
} }

View File

@ -1,11 +1,27 @@
/* ! /*!
* CSS color - Resolve, parse, convert CSS color. * CSS color - Resolve, parse, convert CSS color.
* @license MIT * @license MIT
* @copyright asamuzaK (Kazz) * @copyright asamuzaK (Kazz)
* @see {@link https://github.com/asamuzaK/cssColor/blob/main/LICENSE} * @see {@link https://github.com/asamuzaK/cssColor/blob/main/LICENSE}
*/ */
import { cssCalc as csscalc } from './js/css-calc';
import { isGradient } from './js/css-gradient';
import { cssVar } from './js/css-var';
import { extractDashedIdent, isColor as iscolor, splitValue } from './js/util';
export { convert } from './js/convert'; export { convert } from './js/convert';
export { cssCalc } from './js/css-calc';
export { resolve } from './js/resolve'; export { resolve } from './js/resolve';
export { isColor } from './js/util'; /* utils */
export const utils = {
cssCalc: csscalc,
cssVar,
extractDashedIdent,
isColor: iscolor,
isGradient,
splitValue
};
/* TODO: remove later */
/* alias */
export const isColor = utils.isColor;
export const cssCalc = utils.cssCalc;

114
node_modules/@asamuzakjp/css-color/src/js/cache.ts generated vendored Normal file
View File

@ -0,0 +1,114 @@
/**
* cache
*/
import { LRUCache } from 'lru-cache';
import { Options } from './typedef';
import { valueToJsonString } from './util';
/* numeric constants */
const MAX_CACHE = 4096;
/**
* CacheItem
*/
export class CacheItem {
/* private */
#isNull: boolean;
#item: unknown;
/**
* constructor
*/
constructor(item: unknown, isNull: boolean = false) {
this.#item = item;
this.#isNull = !!isNull;
}
get item() {
return this.#item;
}
get isNull() {
return this.#isNull;
}
}
/**
* NullObject
*/
export class NullObject extends CacheItem {
/**
* constructor
*/
constructor() {
super(Symbol('null'), true);
}
}
/*
* lru cache
*/
export const lruCache = new LRUCache({
max: MAX_CACHE
});
/**
* set cache
* @param key - cache key
* @param value - value to cache
* @returns void
*/
export const setCache = (key: string, value: unknown): void => {
if (key) {
if (value === null) {
lruCache.set(key, new NullObject());
} else if (value instanceof CacheItem) {
lruCache.set(key, value);
} else {
lruCache.set(key, new CacheItem(value));
}
}
};
/**
* get cache
* @param key - cache key
* @returns cached item or false otherwise
*/
export const getCache = (key: string): CacheItem | boolean => {
if (key && lruCache.has(key)) {
const item = lruCache.get(key);
if (item instanceof CacheItem) {
return item;
}
// delete unexpected cached item
lruCache.delete(key);
return false;
}
return false;
};
/**
* create cache key
* @param keyData - key data
* @param [opt] - options
* @returns cache key
*/
export const createCacheKey = (
keyData: Record<string, string>,
opt: Options = {}
): string => {
const { customProperty = {}, dimension = {} } = opt;
let cacheKey = '';
if (
keyData &&
Object.keys(keyData).length &&
typeof customProperty.callback !== 'function' &&
typeof dimension.callback !== 'function'
) {
keyData.opt = valueToJsonString(opt);
cacheKey = valueToJsonString(keyData);
}
return cacheKey;
};

File diff suppressed because it is too large Load Diff

View File

@ -1,23 +1,31 @@
/** /**
* common.js * common
*/ */
/* constants */ /* numeric constants */
const TYPE_FROM = 8; const TYPE_FROM = 8;
const TYPE_TO = -1; const TYPE_TO = -1;
/** /**
* get type * get type
* @param {*} o - object to check * @param o - object to check
* @returns {string} - type of object * @returns type of object
*/ */
export const getType = (o: any): string => export const getType = (o: unknown): string =>
Object.prototype.toString.call(o).slice(TYPE_FROM, TYPE_TO); Object.prototype.toString.call(o).slice(TYPE_FROM, TYPE_TO);
/** /**
* is string * is string
* @param {*} o - object to check * @param o - object to check
* @returns {boolean} - result * @returns result
*/ */
export const isString = (o: any): o is string => export const isString = (o: unknown): o is string =>
typeof o === 'string' || o instanceof String; typeof o === 'string' || o instanceof String;
/**
* is string or number
* @param o - object to check
* @returns result
*/
export const isStringOrNumber = (o: unknown): boolean =>
isString(o) || typeof o === 'number';

View File

@ -1,29 +1,28 @@
/** /**
* constant.js * constant
*/ */
/* constants */
export const VAL_COMP = 'computedValue';
export const VAL_SPEC = 'specifiedValue';
/* values and units */ /* values and units */
const _DIGIT = '(?:0|[1-9]\\d*)'; const _DIGIT = '(?:0|[1-9]\\d*)';
const _COMP = 'clamp|max|min'; const _COMPARE = 'clamp|max|min';
const _EXPO = 'exp|hypot|log|pow|sqrt';
const _SIGN = 'abs|sign';
const _STEP = 'mod|rem|round'; const _STEP = 'mod|rem|round';
const _TRIG = 'a?(?:cos|sin|tan)|atan2'; const _TRIG = 'a?(?:cos|sin|tan)|atan2';
const _EXP = 'exp|hypot|log|pow|sqrt'; const _MATH = `${_COMPARE}|${_EXPO}|${_SIGN}|${_STEP}|${_TRIG}`;
const _SIGN = 'abs|sign';
const _MATH = `${_COMP}|${_STEP}|${_TRIG}|${_EXP}|${_SIGN}`;
const _CALC = `calc|${_MATH}`; const _CALC = `calc|${_MATH}`;
const _VAR = `var|${_CALC}`; const _VAR = `var|${_CALC}`;
export const ANGLE = 'deg|g?rad|turn'; export const ANGLE = 'deg|g?rad|turn';
export const LENGTH =
'[cm]m|[dls]?v(?:[bhiw]|max|min)|in|p[ctx]|q|r?(?:[cl]h|cap|e[mx]|ic)';
export const NUM = `[+-]?(?:${_DIGIT}(?:\\.\\d*)?|\\.\\d+)(?:e-?${_DIGIT})?`; export const NUM = `[+-]?(?:${_DIGIT}(?:\\.\\d*)?|\\.\\d+)(?:e-?${_DIGIT})?`;
export const NUM_POSITIVE = `\\+?(?:${_DIGIT}(?:\\.\\d*)?|\\.\\d+)(?:e-?${_DIGIT})?`;
export const NONE = 'none'; export const NONE = 'none';
export const PCT = `${NUM}%`; export const PCT = `${NUM}%`;
export const SYN_FN_MATH = `^(?:${_MATH})\\($`; export const SYN_FN_CALC = `^(?:${_CALC})\\(|(?<=[*\\/\\s\\(])(?:${_CALC})\\(`;
export const SYN_FN_MATH_CALC = `^(?:${_CALC})\\(|(?<=[*\\/\\s\\(])(?:${_CALC})\\(`; export const SYN_FN_MATH_START = `^(?:${_MATH})\\($`;
export const SYN_FN_MATH_VAR = `^(?:${_VAR})\\(`;
export const SYN_FN_VAR = '^var\\(|(?<=[*\\/\\s\\(])var\\('; export const SYN_FN_VAR = '^var\\(|(?<=[*\\/\\s\\(])var\\(';
export const SYN_FN_VAR_START = `^(?:${_VAR})\\(`;
/* colors */ /* colors */
const _ALPHA = `(?:\\s*\\/\\s*(?:${NUM}|${PCT}|${NONE}))?`; const _ALPHA = `(?:\\s*\\/\\s*(?:${NUM}|${PCT}|${NONE}))?`;
@ -42,7 +41,8 @@ export const CS_LCH = '(?:ok)?lch';
export const CS_SRGB = 'srgb(?:-linear)?'; export const CS_SRGB = 'srgb(?:-linear)?';
export const CS_RGB = `(?:a98|prophoto)-rgb|display-p3|rec2020|${CS_SRGB}`; export const CS_RGB = `(?:a98|prophoto)-rgb|display-p3|rec2020|${CS_SRGB}`;
export const CS_XYZ = 'xyz(?:-d(?:50|65))?'; export const CS_XYZ = 'xyz(?:-d(?:50|65))?';
export const CS_MIX = `${CS_HUE}|${CS_LAB}|${CS_SRGB}|${CS_XYZ}`; export const CS_RECT = `${CS_LAB}|${CS_RGB}|${CS_XYZ}`;
export const CS_MIX = `${CS_HUE}|${CS_RECT}`;
export const FN_COLOR = 'color('; export const FN_COLOR = 'color(';
export const FN_MIX = 'color-mix('; export const FN_MIX = 'color-mix(';
export const FN_REL = `(?:${_COLOR_FUNC})\\(\\s*from\\s+`; export const FN_REL = `(?:${_COLOR_FUNC})\\(\\s*from\\s+`;
@ -59,3 +59,8 @@ export const SYN_COLOR_TYPE = `${_COLOR_KEY}|hsla?\\(\\s*${SYN_HSL_LV3}\\s*\\)|r
export const SYN_MIX_PART = `(?:${SYN_COLOR_TYPE})(?:\\s+${PCT})?`; export const SYN_MIX_PART = `(?:${SYN_COLOR_TYPE})(?:\\s+${PCT})?`;
export const SYN_MIX = `color-mix\\(\\s*in\\s+(?:${CS_MIX})\\s*,\\s*${SYN_MIX_PART}\\s*,\\s*${SYN_MIX_PART}\\s*\\)`; export const SYN_MIX = `color-mix\\(\\s*in\\s+(?:${CS_MIX})\\s*,\\s*${SYN_MIX_PART}\\s*,\\s*${SYN_MIX_PART}\\s*\\)`;
export const SYN_MIX_CAPT = `color-mix\\(\\s*in\\s+(${CS_MIX})\\s*,\\s*(${SYN_MIX_PART})\\s*,\\s*(${SYN_MIX_PART})\\s*\\)`; export const SYN_MIX_CAPT = `color-mix\\(\\s*in\\s+(${CS_MIX})\\s*,\\s*(${SYN_MIX_PART})\\s*,\\s*(${SYN_MIX_PART})\\s*\\)`;
/* formats */
export const VAL_COMP = 'computedValue';
export const VAL_MIX = 'mixValue';
export const VAL_SPEC = 'specifiedValue';

View File

@ -1,8 +1,14 @@
/** /**
* convert.js * convert
*/ */
import { LRUCache } from 'lru-cache'; import {
CacheItem,
NullObject,
createCacheKey,
getCache,
setCache
} from './cache';
import { import {
convertColorToHsl, convertColorToHsl,
convertColorToHwb, convertColorToHwb,
@ -17,571 +23,434 @@ import {
} from './color'; } from './color';
import { isString } from './common'; import { isString } from './common';
import { cssCalc } from './css-calc'; import { cssCalc } from './css-calc';
import { cssVar } from './css-var'; import { resolveVar } from './css-var';
import { resolveRelativeColor } from './relative-color'; import { resolveRelativeColor } from './relative-color';
import { resolve } from './resolve'; import { resolveColor } from './resolve';
import { valueToJsonString } from './util'; import { ColorChannels, ComputedColorChannels, Options } from './typedef';
/* constants */ /* constants */
import { import { SYN_FN_CALC, SYN_FN_REL, SYN_FN_VAR, VAL_COMP } from './constant';
SYN_FN_MATH_CALC, const NAMESPACE = 'convert';
SYN_FN_REL,
SYN_FN_VAR,
VAL_COMP
} from './constant.js';
/* regexp */ /* regexp */
const REG_FN_MATH_CALC = new RegExp(SYN_FN_MATH_CALC); const REG_FN_CALC = new RegExp(SYN_FN_CALC);
const REG_FN_REL = new RegExp(SYN_FN_REL); const REG_FN_REL = new RegExp(SYN_FN_REL);
const REG_FN_VAR = new RegExp(SYN_FN_VAR); const REG_FN_VAR = new RegExp(SYN_FN_VAR);
/* cached results */
export const cachedResults = new LRUCache({
max: 4096
});
/** /**
* pre process * pre process
* @param {string} value - color value * @param value - CSS color value
* @param {object} [opt] - options * @param [opt] - options
* @param {object} [opt.customProperty] - custom properties * @returns value
* @param {object} [opt.dimension] - dimension
* @returns {?string} - value
*/ */
export const preProcess = ( export const preProcess = (
value: string, value: string,
opt: { opt: Options = {}
customProperty?: object; ): string | NullObject => {
dimension?: object;
format?: string;
} = {}
): string | null => {
if (isString(value)) { if (isString(value)) {
value = value.trim(); value = value.trim();
if (!value) { if (!value) {
return null; return new NullObject();
} }
} else { } else {
return null; return new NullObject();
} }
const { customProperty } = opt; const cacheKey: string = createCacheKey(
let cacheKey; {
if ( namespace: NAMESPACE,
typeof ( name: 'preProcess',
customProperty as { callback?: (item: string) => string } value
)?.callback !== 'function' },
) { opt
cacheKey = `{preProcess:${value},opt:${valueToJsonString(opt)}}`; );
if (cachedResults.has(cacheKey)) { const cachedResult = getCache(cacheKey);
return cachedResults.get(cacheKey) as string | null; if (cachedResult instanceof CacheItem) {
if (cachedResult.isNull) {
return cachedResult as NullObject;
} }
return cachedResult.item as string;
} }
if (REG_FN_VAR.test(value)) { if (REG_FN_VAR.test(value)) {
const resolvedValue = cssVar(value, opt) as string | null; const resolvedValue = resolveVar(value, opt);
if (resolvedValue) { if (isString(resolvedValue)) {
value = resolvedValue as string; value = resolvedValue;
} else { } else {
if (cacheKey) { setCache(cacheKey, null);
cachedResults.set(cacheKey, resolvedValue!); return new NullObject();
}
return null;
} }
} }
if (REG_FN_REL.test(value)) { if (REG_FN_REL.test(value)) {
value = resolveRelativeColor(value, opt) as string; const resolvedValue = resolveRelativeColor(value, opt);
} else if (REG_FN_MATH_CALC.test(value)) { if (isString(resolvedValue)) {
const resolvedValue = cssCalc(value, opt) as string | null; value = resolvedValue;
if (resolvedValue) {
value = resolvedValue as string;
} else { } else {
if (cacheKey) { setCache(cacheKey, null);
cachedResults.set(cacheKey, resolvedValue!); return new NullObject();
}
return null;
} }
} else if (REG_FN_CALC.test(value)) {
value = cssCalc(value, opt);
} }
if (value.startsWith('color-mix')) { if (value.startsWith('color-mix')) {
value = resolve(value, { const clonedOpt = structuredClone(opt);
format: VAL_COMP clonedOpt.format = VAL_COMP;
}) as string; clonedOpt.nullable = true;
} const resolvedValue = resolveColor(value, clonedOpt);
if (cacheKey) { setCache(cacheKey, resolvedValue);
cachedResults.set(cacheKey, value); return resolvedValue;
} }
setCache(cacheKey, value);
return value; return value;
}; };
/** /**
* convert number to hex string * convert number to hex string
* @param {number} value - color value * @param value - numeric value
* @returns {string} - hex string: 00..ff * @returns hex string: 00..ff
*/ */
export const numberToHex = (value: number): string => { export const numberToHex = (value: number): string => {
const cacheKey = typeof value === 'number' && `{numberToHex:${value}}`;
if (cacheKey && cachedResults.has(cacheKey)) {
return cachedResults.get(cacheKey) as string;
}
const hex = numberToHexString(value); const hex = numberToHexString(value);
if (cacheKey) {
cachedResults.set(cacheKey, hex);
}
return hex; return hex;
}; };
/** /**
* convert color to hex * convert color to hex
* @param {string} value - color value * @param value - CSS color value
* @param {object} [opt] - options * @param [opt] - options
* @param {boolean} [opt.alpha] - return in #rrggbbaa notation * @param [opt.alpha] - enable alpha channel
* @param {object} [opt.customProperty] - custom properties * @returns #rrggbb | #rrggbbaa | null
* @param {object} [opt.dimension] - dimension
* @returns {?string} - #rrggbb | #rrggbbaa | null
*/ */
export const colorToHex = ( export const colorToHex = (value: string, opt: Options = {}): string | null => {
value: string,
opt: {
alpha?: boolean;
customProperty?: object;
dimension?: object;
format?: string;
} = {}
): string | null => {
if (isString(value)) { if (isString(value)) {
const resolvedValue = preProcess(value, opt) as string | null; const resolvedValue = preProcess(value, opt);
if (resolvedValue) { if (resolvedValue instanceof NullObject) {
value = resolvedValue.toLowerCase() as string; return null;
} else {
return null!;
} }
value = resolvedValue.toLowerCase();
} else { } else {
throw new TypeError(`${value} is not a string.`); throw new TypeError(`${value} is not a string.`);
} }
const { alpha, customProperty } = opt; const { alpha = false } = opt;
let cacheKey; const cacheKey: string = createCacheKey(
if ( {
typeof ( namespace: NAMESPACE,
customProperty as { callback?: (item: string) => string } name: 'colorToHex',
)?.callback !== 'function' value
) { },
cacheKey = `{colorToHex:${value},opt:${valueToJsonString(opt)}}`; opt
if (cachedResults.has(cacheKey)) { );
return cachedResults.get(cacheKey) as string | null; const cachedResult = getCache(cacheKey);
if (cachedResult instanceof CacheItem) {
if (cachedResult.isNull) {
return null;
} }
return cachedResult.item as string;
} }
let hex; let hex;
opt.nullable = true;
if (alpha) { if (alpha) {
opt.format = 'hexAlpha'; opt.format = 'hexAlpha';
hex = resolve(value, opt) as string | null; hex = resolveColor(value, opt);
} else { } else {
opt.format = 'hex'; opt.format = 'hex';
hex = resolve(value, opt) as string | null; hex = resolveColor(value, opt);
} }
if (cacheKey) { if (isString(hex)) {
cachedResults.set(cacheKey, hex!); setCache(cacheKey, hex);
return hex;
} }
return hex; setCache(cacheKey, null);
return null;
}; };
/** /**
* convert color to hsl * convert color to hsl
* @param {string} value - color value * @param value - CSS color value
* @param {object} [opt] - options * @param [opt] - options
* @param {object} [opt.customProperty] - custom properties * @returns ColorChannels - [h, s, l, alpha]
* @param {object} [opt.dimension] - dimension
* @returns {Array.<number>} - [h, s, l, alpha]
*/ */
export const colorToHsl = ( export const colorToHsl = (value: string, opt: Options = {}): ColorChannels => {
value: string,
opt: {
customProperty?: object;
dimension?: object;
format?: string;
} = {}
): Array<number> => {
if (isString(value)) { if (isString(value)) {
const resolvedValue = preProcess(value, opt) as string | null; const resolvedValue = preProcess(value, opt);
if (resolvedValue) { if (resolvedValue instanceof NullObject) {
value = resolvedValue.toLowerCase() as string;
} else {
return [0, 0, 0, 0]; return [0, 0, 0, 0];
} }
value = resolvedValue.toLowerCase();
} else { } else {
throw new TypeError(`${value} is not a string.`); throw new TypeError(`${value} is not a string.`);
} }
const { customProperty } = opt; const cacheKey: string = createCacheKey(
let cacheKey; {
if ( namespace: NAMESPACE,
typeof ( name: 'colorToHsl',
customProperty as { callback?: (item: string) => string } value
)?.callback !== 'function' },
) { opt
cacheKey = `{colorToHsl:${value},opt:${valueToJsonString(opt)}}`; );
if (cachedResults.has(cacheKey)) { const cachedResult = getCache(cacheKey);
return cachedResults.get(cacheKey) as Array<number>; if (cachedResult instanceof CacheItem) {
} return cachedResult.item as ColorChannels;
} }
opt.format = 'hsl'; opt.format = 'hsl';
const hsl = convertColorToHsl(value, opt) as Array<number>; const hsl = convertColorToHsl(value, opt) as ColorChannels;
if (cacheKey) { setCache(cacheKey, hsl);
cachedResults.set(cacheKey, hsl);
}
return hsl; return hsl;
}; };
/** /**
* convert color to hwb * convert color to hwb
* @param {string} value - color value * @param value - CSS color value
* @param {object} [opt] - options * @param [opt] - options
* @param {object} [opt.customProperty] - custom properties * @returns ColorChannels - [h, w, b, alpha]
* @param {object} [opt.dimension] - dimension
* @returns {Array.<number>} - [h, w, b, alpha]
*/ */
export const colorToHwb = ( export const colorToHwb = (value: string, opt: Options = {}): ColorChannels => {
value: string,
opt: {
customProperty?: object;
dimension?: object;
format?: string;
} = {}
): Array<number> => {
if (isString(value)) { if (isString(value)) {
const resolvedValue = preProcess(value, opt) as string | null; const resolvedValue = preProcess(value, opt);
if (resolvedValue) { if (resolvedValue instanceof NullObject) {
value = resolvedValue.toLowerCase() as string;
} else {
return [0, 0, 0, 0]; return [0, 0, 0, 0];
} }
value = resolvedValue.toLowerCase();
} else { } else {
throw new TypeError(`${value} is not a string.`); throw new TypeError(`${value} is not a string.`);
} }
const { customProperty } = opt; const cacheKey: string = createCacheKey(
let cacheKey; {
if ( namespace: NAMESPACE,
typeof ( name: 'colorToHwb',
customProperty as { callback?: (item: string) => string } value
)?.callback !== 'function' },
) { opt
cacheKey = `{colorToHwb:${value},opt:${valueToJsonString(opt)}}`; );
if (cachedResults.has(cacheKey)) { const cachedResult = getCache(cacheKey);
return cachedResults.get(cacheKey) as Array<number>; if (cachedResult instanceof CacheItem) {
} return cachedResult.item as ColorChannels;
} }
opt.format = 'hwb'; opt.format = 'hwb';
const hwb = convertColorToHwb(value, opt) as Array<number>; const hwb = convertColorToHwb(value, opt) as ColorChannels;
if (cacheKey) { setCache(cacheKey, hwb);
cachedResults.set(cacheKey, hwb);
}
return hwb; return hwb;
}; };
/** /**
* convert color to lab * convert color to lab
* @param {string} value - color value * @param value - CSS color value
* @param {object} [opt] - options * @param [opt] - options
* @param {object} [opt.customProperty] - custom properties * @returns ColorChannels - [l, a, b, alpha]
* @param {object} [opt.dimension] - dimension
* @returns {Array.<number>} - [l, a, b, alpha]
*/ */
export const colorToLab = ( export const colorToLab = (value: string, opt: Options = {}): ColorChannels => {
value: string,
opt: {
customProperty?: object;
dimension?: object;
format?: string;
} = {}
): Array<number> => {
if (isString(value)) { if (isString(value)) {
const resolvedValue = preProcess(value, opt) as string | null; const resolvedValue = preProcess(value, opt);
if (resolvedValue) { if (resolvedValue instanceof NullObject) {
value = resolvedValue.toLowerCase() as string;
} else {
return [0, 0, 0, 0]; return [0, 0, 0, 0];
} }
value = resolvedValue.toLowerCase();
} else { } else {
throw new TypeError(`${value} is not a string.`); throw new TypeError(`${value} is not a string.`);
} }
const { customProperty } = opt; const cacheKey: string = createCacheKey(
let cacheKey; {
if ( namespace: NAMESPACE,
typeof ( name: 'colorToLab',
customProperty as { callback?: (item: string) => string } value
)?.callback !== 'function' },
) { opt
cacheKey = `{colorToLab:${value},opt:${valueToJsonString(opt)}}`; );
if (cachedResults.has(cacheKey)) { const cachedResult = getCache(cacheKey);
return cachedResults.get(cacheKey) as Array<number>; if (cachedResult instanceof CacheItem) {
} return cachedResult.item as ColorChannels;
}
const lab = convertColorToLab(value, opt) as Array<number>;
if (cacheKey) {
cachedResults.set(cacheKey, lab);
} }
const lab = convertColorToLab(value, opt) as ColorChannels;
setCache(cacheKey, lab);
return lab; return lab;
}; };
/** /**
* convert color to lch * convert color to lch
* @param {string} value - color value * @param value - CSS color value
* @param {object} [opt] - options * @param [opt] - options
* @param {object} [opt.customProperty] - custom properties * @returns ColorChannels - [l, c, h, alpha]
* @param {object} [opt.dimension] - dimension
* @returns {Array.<number>} - [l, c, h, alpha]
*/ */
export const colorToLch = ( export const colorToLch = (value: string, opt: Options = {}): ColorChannels => {
value: string,
opt: {
customProperty?: object;
dimension?: object;
format?: string;
} = {}
): Array<number> => {
if (isString(value)) { if (isString(value)) {
const resolvedValue = preProcess(value, opt) as string | null; const resolvedValue = preProcess(value, opt);
if (resolvedValue) { if (resolvedValue instanceof NullObject) {
value = resolvedValue.toLowerCase() as string;
} else {
return [0, 0, 0, 0]; return [0, 0, 0, 0];
} }
value = resolvedValue.toLowerCase();
} else { } else {
throw new TypeError(`${value} is not a string.`); throw new TypeError(`${value} is not a string.`);
} }
const { customProperty } = opt; const cacheKey: string = createCacheKey(
let cacheKey; {
if ( namespace: NAMESPACE,
typeof ( name: 'colorToLch',
customProperty as { callback?: (item: string) => string } value
)?.callback !== 'function' },
) { opt
cacheKey = `{colorToLch:${value},opt:${valueToJsonString(opt)}}`; );
if (cachedResults.has(cacheKey)) { const cachedResult = getCache(cacheKey);
return cachedResults.get(cacheKey) as Array<number>; if (cachedResult instanceof CacheItem) {
} return cachedResult.item as ColorChannels;
}
const lch = convertColorToLch(value, opt) as Array<number>;
if (cacheKey) {
cachedResults.set(cacheKey, lch);
} }
const lch = convertColorToLch(value, opt) as ColorChannels;
setCache(cacheKey, lch);
return lch; return lch;
}; };
/** /**
* convert color to oklab * convert color to oklab
* @param {string} value - color value * @param value - CSS color value
* @param {object} [opt] - options * @param [opt] - options
* @param {object} [opt.customProperty] - custom properties * @returns ColorChannels - [l, a, b, alpha]
* @param {object} [opt.dimension] - dimension
* @returns {Array.<number>} - [l, a, b, alpha]
*/ */
export const colorToOklab = ( export const colorToOklab = (
value: string, value: string,
opt: { opt: Options = {}
customProperty?: object; ): ColorChannels => {
dimension?: object;
format?: string;
} = {}
): Array<number> => {
if (isString(value)) { if (isString(value)) {
const resolvedValue = preProcess(value, opt) as string | null; const resolvedValue = preProcess(value, opt);
if (resolvedValue) { if (resolvedValue instanceof NullObject) {
value = resolvedValue.toLowerCase() as string;
} else {
return [0, 0, 0, 0]; return [0, 0, 0, 0];
} }
value = resolvedValue.toLowerCase();
} else { } else {
throw new TypeError(`${value} is not a string.`); throw new TypeError(`${value} is not a string.`);
} }
const { customProperty } = opt; const cacheKey: string = createCacheKey(
let cacheKey; {
if ( namespace: NAMESPACE,
typeof ( name: 'colorToOklab',
customProperty as { callback?: (item: string) => string } value
)?.callback !== 'function' },
) { opt
cacheKey = `{colorToOklab:${value},opt:${valueToJsonString(opt)}}`; );
if (cachedResults.has(cacheKey)) { const cachedResult = getCache(cacheKey);
return cachedResults.get(cacheKey) as Array<number>; if (cachedResult instanceof CacheItem) {
} return cachedResult.item as ColorChannels;
}
const lab = convertColorToOklab(value, opt) as Array<number>;
if (cacheKey) {
cachedResults.set(cacheKey, lab);
} }
const lab = convertColorToOklab(value, opt) as ColorChannels;
setCache(cacheKey, lab);
return lab; return lab;
}; };
/** /**
* convert color to oklch * convert color to oklch
* @param {string} value - color value * @param value - CSS color value
* @param {object} [opt] - options * @param [opt] - options
* @param {object} [opt.customProperty] - custom properties * @returns ColorChannels - [l, c, h, alpha]
* @param {object} [opt.dimension] - dimension
* @returns {Array.<number>} - [l, c, h, alpha]
*/ */
export const colorToOklch = ( export const colorToOklch = (
value: string, value: string,
opt: { opt: Options = {}
customProperty?: object; ): ColorChannels => {
dimension?: object;
format?: string;
} = {}
): Array<number> => {
if (isString(value)) { if (isString(value)) {
const resolvedValue = preProcess(value, opt) as string | null; const resolvedValue = preProcess(value, opt);
if (resolvedValue) { if (resolvedValue instanceof NullObject) {
value = resolvedValue.toLowerCase() as string;
} else {
return [0, 0, 0, 0]; return [0, 0, 0, 0];
} }
value = resolvedValue.toLowerCase();
} else { } else {
throw new TypeError(`${value} is not a string.`); throw new TypeError(`${value} is not a string.`);
} }
const { customProperty } = opt; const cacheKey: string = createCacheKey(
let cacheKey; {
if ( namespace: NAMESPACE,
typeof ( name: 'colorToOklch',
customProperty as { callback?: (item: string) => string } value
)?.callback !== 'function' },
) { opt
cacheKey = `{colorToOklch:${value},opt:${valueToJsonString(opt)}}`; );
if (cachedResults.has(cacheKey)) { const cachedResult = getCache(cacheKey);
return cachedResults.get(cacheKey) as Array<number>; if (cachedResult instanceof CacheItem) {
} return cachedResult.item as ColorChannels;
}
const lch = convertColorToOklch(value, opt) as Array<number>;
if (cacheKey) {
cachedResults.set(cacheKey, lch);
} }
const lch = convertColorToOklch(value, opt) as ColorChannels;
setCache(cacheKey, lch);
return lch; return lch;
}; };
/** /**
* convert color to rgb * convert color to rgb
* @param {string} value - color value * @param value - CSS color value
* @param {object} [opt] - options * @param [opt] - options
* @param {object} [opt.customProperty] - custom properties * @returns ColorChannels - [r, g, b, alpha]
* @param {object} [opt.dimension] - dimension
* @returns {Array.<number>} - [r, g, b, alpha]
*/ */
export const colorToRgb = ( export const colorToRgb = (value: string, opt: Options = {}): ColorChannels => {
value: string,
opt: {
customProperty?: object;
dimension?: object;
format?: string;
} = {}
): Array<number> => {
if (isString(value)) { if (isString(value)) {
const resolvedValue = preProcess(value, opt) as string | null; const resolvedValue = preProcess(value, opt);
if (resolvedValue) { if (resolvedValue instanceof NullObject) {
value = resolvedValue.toLowerCase() as string;
} else {
return [0, 0, 0, 0]; return [0, 0, 0, 0];
} }
value = resolvedValue.toLowerCase();
} else { } else {
throw new TypeError(`${value} is not a string.`); throw new TypeError(`${value} is not a string.`);
} }
const { customProperty } = opt; const cacheKey: string = createCacheKey(
let cacheKey; {
if ( namespace: NAMESPACE,
typeof ( name: 'colorToRgb',
customProperty as { callback?: (item: string) => string } value
)?.callback !== 'function' },
) { opt
cacheKey = `{colorToRgb:${value},opt:${valueToJsonString(opt)}}`; );
if (cachedResults.has(cacheKey)) { const cachedResult = getCache(cacheKey);
return cachedResults.get(cacheKey) as Array<number>; if (cachedResult instanceof CacheItem) {
} return cachedResult.item as ColorChannels;
}
const rgb = convertColorToRgb(value, opt) as Array<number>;
if (cacheKey) {
cachedResults.set(cacheKey, rgb);
} }
const rgb = convertColorToRgb(value, opt) as ColorChannels;
setCache(cacheKey, rgb);
return rgb; return rgb;
}; };
/** /**
* convert color to xyz * convert color to xyz
* @param {string} value - color value * @param value - CSS color value
* @param {object} [opt] - options * @param [opt] - options
* @param {object} [opt.customProperty] - custom properties * @returns ColorChannels - [x, y, z, alpha]
* @param {object} [opt.d50] - white poin in d50
* @param {object} [opt.dimension] - dimension
* @returns {Array.<number>} - [x, y, z, alpha]
*/ */
export const colorToXyz = ( export const colorToXyz = (value: string, opt: Options = {}): ColorChannels => {
value: string,
opt: {
customProperty?: object;
d50?: boolean;
dimension?: object;
format?: string;
} = {}
): Array<number> => {
if (isString(value)) { if (isString(value)) {
const resolvedValue = preProcess(value, opt) as string | null; const resolvedValue = preProcess(value, opt);
if (resolvedValue) { if (resolvedValue instanceof NullObject) {
value = resolvedValue.toLowerCase() as string;
} else {
return [0, 0, 0, 0]; return [0, 0, 0, 0];
} }
value = resolvedValue.toLowerCase();
} else { } else {
throw new TypeError(`${value} is not a string.`); throw new TypeError(`${value} is not a string.`);
} }
const { customProperty } = opt; const cacheKey: string = createCacheKey(
let cacheKey; {
if ( namespace: NAMESPACE,
typeof ( name: 'colorToXyz',
customProperty as { callback?: (item: string) => string } value
)?.callback !== 'function' },
) { opt
cacheKey = `{colorToXyz:${value},opt:${valueToJsonString(opt)}}`; );
if (cachedResults.has(cacheKey)) { const cachedResult = getCache(cacheKey);
return cachedResults.get(cacheKey) as Array<number>; if (cachedResult instanceof CacheItem) {
} return cachedResult.item as ColorChannels;
} }
let xyz; let xyz;
if (value.startsWith('color(')) { if (value.startsWith('color(')) {
[, ...xyz] = parseColorFunc(value, opt) as [ [, ...xyz] = parseColorFunc(value, opt) as ComputedColorChannels;
string,
number,
number,
number,
number
];
} else { } else {
[, ...xyz] = parseColorValue(value, opt) as [ [, ...xyz] = parseColorValue(value, opt) as ComputedColorChannels;
string,
number,
number,
number,
number
];
} }
if (cacheKey) { setCache(cacheKey, xyz);
cachedResults.set(cacheKey, xyz as Array<number>); return xyz as ColorChannels;
}
return xyz as Array<number>;
}; };
/** /**
* convert color to xyz-d50 * convert color to xyz-d50
* @param {string} value - color value * @param value - CSS color value
* @param {object} [opt] - options * @param [opt] - options
* @param {object} [opt.customProperty] - custom properties * @returns ColorChannels - [x, y, z, alpha]
* @param {object} [opt.dimension] - dimension
* @returns {Array.<number>} - [x, y, z, alpha]
*/ */
export const colorToXyzD50 = ( export const colorToXyzD50 = (
value: string, value: string,
opt: { opt: Options = {}
customProperty?: object; ): ColorChannels => {
d50?: boolean;
dimension?: object;
format?: string;
} = {}
): Array<number> => {
opt.d50 = true; opt.d50 = true;
return colorToXyz(value, opt) as Array<number>; return colorToXyz(value, opt);
}; };
/* convert */ /* convert */

View File

@ -1,23 +1,32 @@
/** /**
* css-calc.js * css-calc
*/ */
import { calc } from '@csstools/css-calc'; import { calc } from '@csstools/css-calc';
import { TokenType, tokenize } from '@csstools/css-tokenizer'; import { CSSToken, TokenType, tokenize } from '@csstools/css-tokenizer';
import { LRUCache } from 'lru-cache'; import {
import { isString } from './common'; CacheItem,
import { roundToPrecision, valueToJsonString } from './util'; NullObject,
createCacheKey,
getCache,
setCache
} from './cache';
import { isString, isStringOrNumber } from './common';
import { resolveVar } from './css-var';
import { roundToPrecision } from './util';
import { MatchedRegExp, Options } from './typedef';
/* constants */ /* constants */
import { import {
FN_VAR, ANGLE,
LENGTH,
NUM, NUM,
SYN_FN_MATH, SYN_FN_CALC,
SYN_FN_MATH_CALC, SYN_FN_MATH_START,
SYN_FN_MATH_VAR,
SYN_FN_VAR, SYN_FN_VAR,
SYN_FN_VAR_START,
VAL_SPEC VAL_SPEC
} from './constant.js'; } from './constant';
const { const {
CloseParen: PAREN_CLOSE, CloseParen: PAREN_CLOSE,
Comment: COMMENT, Comment: COMMENT,
@ -27,49 +36,48 @@ const {
OpenParen: PAREN_OPEN, OpenParen: PAREN_OPEN,
Whitespace: W_SPACE Whitespace: W_SPACE
} = TokenType; } = TokenType;
const NAMESPACE = 'css-calc';
/* numeric constants */
const TRIA = 3;
const HEX = 16; const HEX = 16;
const MAX_PCT = 100; const MAX_PCT = 100;
/* regexp */ /* regexp */
const REG_FN_MATH_CALC = new RegExp(SYN_FN_MATH_CALC); const REG_FN_CALC = new RegExp(SYN_FN_CALC);
const REG_FN_MATH_START = new RegExp(SYN_FN_MATH_START);
const REG_FN_VAR = new RegExp(SYN_FN_VAR); const REG_FN_VAR = new RegExp(SYN_FN_VAR);
const REG_FN_VAR_START = new RegExp(SYN_FN_VAR_START);
const REG_OPERATOR = /\s[*+/-]\s/; const REG_OPERATOR = /\s[*+/-]\s/;
const REG_START_MATH = new RegExp(SYN_FN_MATH); const REG_TYPE_DIM = new RegExp(`^(${NUM})(${ANGLE}|${LENGTH})$`);
const REG_START_MATH_VAR = new RegExp(SYN_FN_MATH_VAR); const REG_TYPE_DIM_PCT = new RegExp(`^(${NUM})(${ANGLE}|${LENGTH}|%)$`);
const REG_TYPE_DIM = new RegExp(`^(${NUM})([a-z]+)$`);
const REG_TYPE_DIM_PCT = new RegExp(`^(${NUM})([a-z]+|%)$`);
const REG_TYPE_PCT = new RegExp(`^(${NUM})%$`); const REG_TYPE_PCT = new RegExp(`^(${NUM})%$`);
/* cached results */
export const cachedResults = new LRUCache({
max: 4096
});
/** /**
* calclator * Calclator
*/ */
export class Calculator { export class Calculator {
/* private */ /* private */
// number // number
#hasNum: boolean; #hasNum: boolean;
#numSum: Array<any>; #numSum: number[];
#numMul: Array<any>; #numMul: number[];
// percentage // percentage
#hasPct: boolean; #hasPct: boolean;
#pctSum: Array<any>; #pctSum: number[];
#pctMul: Array<any>; #pctMul: number[];
// dimension // dimension
#hasDim: boolean; #hasDim: boolean;
#dimSum: Array<any>; #dimSum: string[];
#dimSub: Array<any>; #dimSub: string[];
#dimMul: Array<any>; #dimMul: string[];
#dimDiv: Array<any>; #dimDiv: string[];
// et cetra // et cetra
#hasEtc: boolean; #hasEtc: boolean;
#etcSum: Array<any>; #etcSum: string[];
#etcSub: Array<any>; #etcSub: string[];
#etcMul: Array<any>; #etcMul: string[];
#etcDiv: Array<any>; #etcDiv: string[];
/** /**
* constructor * constructor
@ -179,7 +187,7 @@ export class Calculator {
/** /**
* clear values * clear values
* @returns {void} * @returns void
*/ */
clear() { clear() {
// number // number
@ -206,25 +214,17 @@ export class Calculator {
/** /**
* sort values * sort values
* @param {Array} values - values * @param values - values
* @returns {Array} - sorted values * @returns sorted values
*/ */
sort(values: Array<any> = []): Array<any> { sort(values: string[] = []): string[] {
const arr = [...values]; const arr = [...values];
if (arr.length > 1) { if (arr.length > 1) {
arr.sort((a, b) => { arr.sort((a, b) => {
let res; let res;
if (REG_TYPE_DIM_PCT.test(a) && REG_TYPE_DIM_PCT.test(b)) { if (REG_TYPE_DIM_PCT.test(a) && REG_TYPE_DIM_PCT.test(b)) {
const [, valA, unitA] = a.match(REG_TYPE_DIM_PCT) as [ const [, valA, unitA] = a.match(REG_TYPE_DIM_PCT) as MatchedRegExp;
string, const [, valB, unitB] = b.match(REG_TYPE_DIM_PCT) as MatchedRegExp;
string,
string
];
const [, valB, unitB] = b.match(REG_TYPE_DIM_PCT) as [
string,
string,
string
];
if (unitA === unitB) { if (unitA === unitB) {
if (Number(valA) === Number(valB)) { if (Number(valA) === Number(valB)) {
res = 0; res = 0;
@ -255,11 +255,11 @@ export class Calculator {
/** /**
* multiply values * multiply values
* @returns {?string} - resolved value * @returns resolved value
*/ */
multiply(): string | null { multiply(): string {
const value = []; const value = [];
let num!: number | string; let num;
if (this.#hasNum) { if (this.#hasNum) {
num = 1; num = 1;
for (const i of this.#numMul) { for (const i of this.#numMul) {
@ -269,38 +269,43 @@ export class Calculator {
} }
} }
if (!this.#hasPct && !this.#hasDim && !this.hasEtc) { if (!this.#hasPct && !this.#hasDim && !this.hasEtc) {
if (Number.isFinite(num)) {
num = roundToPrecision(num, HEX);
}
value.push(num); value.push(num);
} }
} }
if (this.#hasPct) { if (this.#hasPct) {
if (!this.#hasNum) { if (typeof num !== 'number') {
num = 1; num = 1;
} }
for (const i of this.#pctMul) { for (const i of this.#pctMul) {
(num as number) *= i; num *= i;
if (num === 0 || !Number.isFinite(num) || Number.isNaN(num)) { if (num === 0 || !Number.isFinite(num) || Number.isNaN(num)) {
break; break;
} }
} }
if (Number.isFinite(num)) { if (Number.isFinite(num)) {
num = `${num}%`; num = `${roundToPrecision(num, HEX)}%`;
} }
if (!this.#hasDim && !this.hasEtc) { if (!this.#hasDim && !this.hasEtc) {
value.push(num); value.push(num);
} }
} }
if (this.#hasDim) { if (this.#hasDim) {
let dim, mul, div; let dim = '';
let mul = '';
let div = '';
if (this.#dimMul.length) { if (this.#dimMul.length) {
if (this.#dimMul.length === 1) { if (this.#dimMul.length === 1) {
[mul] = this.#dimMul; [mul] = this.#dimMul as [string];
} else { } else {
mul = `${this.sort(this.#dimMul).join(' * ')}`; mul = `${this.sort(this.#dimMul).join(' * ')}`;
} }
} }
if (this.#dimDiv.length) { if (this.#dimDiv.length) {
if (this.#dimDiv.length === 1) { if (this.#dimDiv.length === 1) {
[div] = this.#dimDiv; [div] = this.#dimDiv as [string];
} else { } else {
div = `${this.sort(this.#dimDiv).join(' * ')}`; div = `${this.sort(this.#dimDiv).join(' * ')}`;
} }
@ -322,16 +327,14 @@ export class Calculator {
toCanonicalUnits: true toCanonicalUnits: true
}); });
} }
} else if (div.includes('*')) {
dim = calc(`calc(${num} / (${div}))`, {
toCanonicalUnits: true
});
} else { } else {
if (div.includes('*')) { dim = calc(`calc(${num} / ${div})`, {
dim = calc(`calc(${num} / (${div}))`, { toCanonicalUnits: true
toCanonicalUnits: true });
});
} else {
dim = calc(`calc(${num} / ${div})`, {
toCanonicalUnits: true
});
}
} }
value.push(dim.replace(/^calc/, '')); value.push(dim.replace(/^calc/, ''));
} else { } else {
@ -398,14 +401,17 @@ export class Calculator {
} }
} }
} }
return value.join(' ') || null; if (value.length) {
return value.join(' ');
}
return '';
} }
/** /**
* sum values * sum values
* @returns {?string} - resolved value * @returns resolved value
*/ */
sum(): string | null { sum(): string {
const value = []; const value = [];
if (this.#hasNum) { if (this.#hasNum) {
let num = 0; let num = 0;
@ -418,10 +424,10 @@ export class Calculator {
value.push(num); value.push(num);
} }
if (this.#hasPct) { if (this.#hasPct) {
let num = 0 as number | string; let num: number | string = 0;
for (const i of this.#pctSum) { for (const i of this.#pctSum) {
num += i; num += i;
if (!Number.isFinite(num) || Number.isNaN(num)) { if (!Number.isFinite(num)) {
break; break;
} }
} }
@ -472,7 +478,7 @@ export class Calculator {
if (this.#hasEtc) { if (this.#hasEtc) {
if (this.#etcSum.length) { if (this.#etcSum.length) {
const sum = this.sort(this.#etcSum) const sum = this.sort(this.#etcSum)
.map((item) => { .map(item => {
let res; let res;
if ( if (
REG_OPERATOR.test(item) && REG_OPERATOR.test(item) &&
@ -498,7 +504,7 @@ export class Calculator {
} }
if (this.#etcSub.length) { if (this.#etcSub.length) {
const sub = this.sort(this.#etcSub) const sub = this.sort(this.#etcSub)
.map((item) => { .map(item => {
let res; let res;
if ( if (
REG_OPERATOR.test(item) && REG_OPERATOR.test(item) &&
@ -525,154 +531,167 @@ export class Calculator {
} }
} }
} }
return value.join(' ') || null; if (value.length) {
return value.join(' ');
}
return '';
} }
} }
/** /**
* sort calc values * sort calc values
* @param {Array} values - values * @param values - values to sort
* @param {boolean} finalize - finalize * @param [finalize] - finalize values
* @returns {?string} - sorted value * @returns sorted values
*/ */
export const sortCalcValues = ( export const sortCalcValues = (
values: string[] = [], values: (number | string)[] = [],
finalize: boolean = false finalize: boolean = false
): string | null => { ): string => {
if (values.length < 3) { if (values.length < TRIA) {
return null; throw new Error(`Unexpected array length ${values.length}.`);
} }
const start = values.shift(); const start = values.shift();
if (!isString(start) || !start.endsWith('(')) {
throw new Error(`Unexpected token ${start}.`);
}
const end = values.pop(); const end = values.pop();
if (end !== ')') {
throw new Error(`Unexpected token ${end}.`);
}
if (values.length === 1) { if (values.length === 1) {
const [value] = values; const [value] = values;
if (!isStringOrNumber(value)) {
throw new Error(`Unexpected token ${value}.`);
}
return `${start}${value}${end}`; return `${start}${value}${end}`;
} }
const sortedValues = []; const sortedValues = [];
const cal = new Calculator(); const cal = new Calculator();
let operator!: string | null; let operator: string = '';
for (let i = 0, l = values.length; i < l; i++) { const l = values.length;
const value = values[i]! as number | string; for (let i = 0; i < l; i++) {
const value = values[i];
if (!isStringOrNumber(value)) {
throw new Error(`Unexpected token ${value}.`);
}
if (value === '*' || value === '/') { if (value === '*' || value === '/') {
operator = value; operator = value;
} else if (value === '+' || value === '-') { } else if (value === '+' || value === '-') {
const sortedValue = cal.multiply(); const sortedValue = cal.multiply();
sortedValues.push(sortedValue, value); if (sortedValue) {
sortedValues.push(sortedValue, value);
}
cal.clear(); cal.clear();
operator = null; operator = '';
} else { } else {
const numValue = Number(value);
const strValue = `${value}`;
switch (operator) { switch (operator) {
case '/': { case '/': {
const numValue = Number(value) as number;
if (Number.isFinite(numValue)) { if (Number.isFinite(numValue)) {
cal.hasNum = true; cal.hasNum = true;
cal.numMul.push(1 / numValue); cal.numMul.push(1 / numValue);
} else if (REG_TYPE_PCT.test(value as string)) { } else if (REG_TYPE_PCT.test(strValue)) {
const [, val] = (value as string).match(REG_TYPE_PCT) as [ const [, val] = strValue.match(REG_TYPE_PCT) as MatchedRegExp;
string,
string
];
cal.hasPct = true; cal.hasPct = true;
cal.pctMul.push((MAX_PCT * MAX_PCT) / Number(val)); cal.pctMul.push((MAX_PCT * MAX_PCT) / Number(val));
} else if (REG_TYPE_DIM.test(value as string)) { } else if (REG_TYPE_DIM.test(strValue)) {
cal.hasDim = true; cal.hasDim = true;
cal.dimDiv.push(value); cal.dimDiv.push(strValue);
} else { } else {
cal.hasEtc = true; cal.hasEtc = true;
cal.etcDiv.push(value); cal.etcDiv.push(strValue);
} }
break; break;
} }
case '*': case '*':
default: { default: {
const numValue = Number(value);
if (Number.isFinite(numValue)) { if (Number.isFinite(numValue)) {
cal.hasNum = true; cal.hasNum = true;
cal.numMul.push(numValue); cal.numMul.push(numValue);
} else if (REG_TYPE_PCT.test(value as string)) { } else if (REG_TYPE_PCT.test(strValue)) {
const [, val] = (value as string).match(REG_TYPE_PCT) as [ const [, val] = strValue.match(REG_TYPE_PCT) as MatchedRegExp;
string,
string
];
cal.hasPct = true; cal.hasPct = true;
cal.pctMul.push(Number(val)); cal.pctMul.push(Number(val));
} else if (REG_TYPE_DIM.test(value as string)) { } else if (REG_TYPE_DIM.test(strValue)) {
cal.hasDim = true; cal.hasDim = true;
cal.dimMul.push(value); cal.dimMul.push(strValue);
} else { } else {
cal.hasEtc = true; cal.hasEtc = true;
cal.etcMul.push(value); cal.etcMul.push(strValue);
}
}
}
}
if (i === l - 1) {
const sortedValue = cal.multiply();
if (sortedValue) {
sortedValues.push(sortedValue);
}
cal.clear();
operator = '';
}
}
let resolvedValue = '';
if (finalize && (sortedValues.includes('+') || sortedValues.includes('-'))) {
const finalizedValues = [];
cal.clear();
operator = '';
const l = sortedValues.length;
for (let i = 0; i < l; i++) {
const value = sortedValues[i];
if (isStringOrNumber(value)) {
if (value === '+' || value === '-') {
operator = value;
} else {
const numValue = Number(value);
const strValue = `${value}`;
switch (operator) {
case '-': {
if (Number.isFinite(numValue)) {
cal.hasNum = true;
cal.numSum.push(-1 * numValue);
} else if (REG_TYPE_PCT.test(strValue)) {
const [, val] = strValue.match(REG_TYPE_PCT) as MatchedRegExp;
cal.hasPct = true;
cal.pctSum.push(-1 * Number(val));
} else if (REG_TYPE_DIM.test(strValue)) {
cal.hasDim = true;
cal.dimSub.push(strValue);
} else {
cal.hasEtc = true;
cal.etcSub.push(strValue);
}
break;
}
case '+':
default: {
if (Number.isFinite(numValue)) {
cal.hasNum = true;
cal.numSum.push(numValue);
} else if (REG_TYPE_PCT.test(strValue)) {
const [, val] = strValue.match(REG_TYPE_PCT) as MatchedRegExp;
cal.hasPct = true;
cal.pctSum.push(Number(val));
} else if (REG_TYPE_DIM.test(strValue)) {
cal.hasDim = true;
cal.dimSum.push(strValue);
} else {
cal.hasEtc = true;
cal.etcSum.push(strValue);
}
}
} }
} }
} }
if (i === l - 1) { if (i === l - 1) {
const sortedValue = cal.multiply(); const sortedValue = cal.sum();
sortedValues.push(sortedValue); if (sortedValue) {
cal.clear();
operator = null;
}
}
}
let resolvedValue;
if (finalize && (sortedValues.includes('+') || sortedValues.includes('-'))) {
const finalizedValues = [];
cal.clear();
operator = null;
for (let i = 0, l = sortedValues.length; i < l; i++) {
const value = sortedValues[i] as number | string;
if (value === '+' || value === '-') {
operator = value;
} else {
switch (operator) {
case '-': {
const numValue = Number(value) as number;
if (Number.isFinite(numValue)) {
cal.hasNum = true;
cal.numSum.push(-1 * numValue);
} else if (REG_TYPE_PCT.test(value as string)) {
const [, val] = (value as string).match(REG_TYPE_PCT) as [
string,
string
];
cal.hasPct = true;
cal.pctSum.push(-1 * Number(val));
} else if (REG_TYPE_DIM.test(value as string)) {
cal.hasDim = true;
cal.dimSub.push(value);
} else {
cal.hasEtc = true;
cal.etcSub.push(value);
}
break;
}
case '+':
default: {
const numValue = Number(value) as number;
if (Number.isFinite(numValue)) {
cal.hasNum = true;
cal.numSum.push(numValue);
} else if (REG_TYPE_PCT.test(value as string)) {
const [, val] = (value as string).match(REG_TYPE_PCT) as [
string,
string
];
cal.hasPct = true;
cal.pctSum.push(Number(val));
} else if (REG_TYPE_DIM.test(value as string)) {
cal.hasDim = true;
cal.dimSum.push(value);
} else {
cal.hasEtc = true;
cal.etcSum.push(value);
}
}
}
if (i === l - 1) {
const sortedValue = cal.sum();
finalizedValues.push(sortedValue); finalizedValues.push(sortedValue);
cal.clear();
operator = null;
} }
cal.clear();
operator = '';
} }
} }
resolvedValue = finalizedValues.join(' '); resolvedValue = finalizedValues.join(' ');
@ -684,164 +703,149 @@ export const sortCalcValues = (
/** /**
* serialize calc * serialize calc
* @param {string} value - value * @param value - CSS value
* @param {object} [opt] - options * @param [opt] - options
* @param {string} [opt.format] - output format * @returns serialized value
* @returns {?string} - resolved value
*/ */
export const serializeCalc = ( export const serializeCalc = (value: string, opt: Options = {}): string => {
value: string, const { format = '' } = opt;
opt: {
format?: string;
} = {}
): string | null => {
const { format } = opt;
if (isString(value)) { if (isString(value)) {
if (!REG_START_MATH_VAR.test(value) || format !== VAL_SPEC) { if (!REG_FN_VAR_START.test(value) || format !== VAL_SPEC) {
return value; return value;
} }
value = value.toLowerCase().trim(); value = value.toLowerCase().trim();
} else { } else {
throw new TypeError(`${value} is not a string`); throw new TypeError(`${value} is not a string.`);
} }
const cacheKey = `{serializeCalc:${value},opt:${valueToJsonString(opt)}}`; const cacheKey: string = createCacheKey(
if (cachedResults.has(cacheKey)) { {
return cachedResults.get(cacheKey) as string | null; namespace: NAMESPACE,
name: 'serializeCalc',
value
},
opt
);
const cachedResult = getCache(cacheKey);
if (cachedResult instanceof CacheItem) {
return cachedResult.item as string;
} }
const items = tokenize({ css: value }) const items: string[] = tokenize({ css: value })
.map((token) => { .map((token: CSSToken): string => {
const [type, value] = token as [string, string]; const [type, value] = token as [TokenType, string];
let res; let res = '';
if (type !== W_SPACE && type !== COMMENT) { if (type !== W_SPACE && type !== COMMENT) {
res = value; res = value;
} }
return res; return res;
}) })
.filter((v: any) => v) as Array<string>; .filter(v => v);
let startIndex = items.findLastIndex((item: string) => /\($/.test(item)); let startIndex = items.findLastIndex((item: string) => /\($/.test(item));
while (startIndex) { while (startIndex) {
const endIndex = items.findIndex((item: any, index: number) => { const endIndex = items.findIndex((item: unknown, index: number) => {
return item === ')' && index > startIndex; return item === ')' && index > startIndex;
}); });
const slicedValues = items.slice(startIndex, endIndex + 1); const slicedValues: string[] = items.slice(startIndex, endIndex + 1);
let serializedValue = let serializedValue: string = sortCalcValues(slicedValues);
sortCalcValues(slicedValues as Array<string>) as string; if (REG_FN_VAR_START.test(serializedValue)) {
if (REG_START_MATH_VAR.test(serializedValue)) {
serializedValue = calc(serializedValue, { serializedValue = calc(serializedValue, {
toCanonicalUnits: true toCanonicalUnits: true
}) as string; });
} }
items.splice(startIndex, endIndex - startIndex + 1, serializedValue); items.splice(startIndex, endIndex - startIndex + 1, serializedValue);
startIndex = items.findLastIndex((item: string) => /\($/.test(item)); startIndex = items.findLastIndex((item: string) => /\($/.test(item));
} }
const serializedCalc = const serializedCalc = sortCalcValues(items, true);
sortCalcValues(items as Array<string>, true) as string | null; setCache(cacheKey, serializedCalc);
if (cacheKey) {
cachedResults.set(cacheKey, serializedCalc!);
}
return serializedCalc; return serializedCalc;
}; };
/** /**
* resolve dimension * resolve dimension
* @param {Array} token - token * @param token - CSS token
* @param {object} [opt] - options * @param [opt] - options
* @param {object} [opt.dimension] - dimension * @returns resolved value
* @returns {?string} - resolved value
*/ */
export const resolveDimension = ( export const resolveDimension = (
token: Array<any>, token: CSSToken,
opt: { opt: Options = {}
dimension?: object; ): string | NullObject => {
} = {}
): string | null => {
if (!Array.isArray(token)) { if (!Array.isArray(token)) {
throw new TypeError(`${token} is not an array.`); throw new TypeError(`${token} is not an array.`);
} }
const [, value, , , detail = {}] = token; const [, , , , detail = {}] = token;
const { unit, value: relativeValue } = detail; const { unit, value } = detail as {
unit: string;
value: number;
};
const { dimension = {} } = opt; const { dimension = {} } = opt;
if (unit === 'px') { if (unit === 'px') {
return value; return `${value}${unit}`;
} }
let res; const relativeValue = Number(value);
if (unit && Number.isFinite(relativeValue as number)) { if (unit && Number.isFinite(relativeValue)) {
let pixelValue!: number | undefined; let pixelValue;
if (Object.hasOwnProperty.call(dimension, unit)) { if (Object.hasOwnProperty.call(dimension, unit)) {
pixelValue = dimension[unit as never]; pixelValue = dimension[unit];
} else if ( } else if (typeof dimension.callback === 'function') {
typeof ( pixelValue = dimension.callback(unit);
dimension as {
callback?: (unit: string) => number;
}
).callback === 'function'
) {
pixelValue = (
dimension as {
callback: (unit: string) => number;
}
).callback(unit);
} }
pixelValue = Number(pixelValue); pixelValue = Number(pixelValue);
if (Number.isFinite(pixelValue)) { if (Number.isFinite(pixelValue)) {
res = `${relativeValue as number * pixelValue as number}px`; return `${relativeValue * pixelValue}px`;
} }
} }
return res ?? null; return new NullObject();
}; };
/** /**
* parse tokens * parse tokens
* @param {Array.<Array>} tokens - tokens * @param tokens - CSS tokens
* @param {object} [opt] - options * @param [opt] - options
* @returns {Array.<string>} - parsed tokens * @returns parsed tokens
*/ */
export const parseTokens = ( export const parseTokens = (
tokens: Array<Array<any>>, tokens: CSSToken[],
opt: { opt: Options = {}
dimension?: object; ): string[] => {
format?: string;
} = {}
): Array<string> => {
if (!Array.isArray(tokens)) { if (!Array.isArray(tokens)) {
throw new TypeError(`${tokens} is not an array.`); throw new TypeError(`${tokens} is not an array.`);
} }
const { format } = opt; const { format = '' } = opt;
const mathFunc = new Set(); const mathFunc = new Set();
let nest = 0 as number; let nest = 0;
const res = [] as string[]; const res: string[] = [];
while (tokens.length) { while (tokens.length) {
const token = tokens.shift(); const token = tokens.shift();
if (!Array.isArray(token)) { if (!Array.isArray(token)) {
throw new TypeError(`${token} is not an array.`); throw new TypeError(`${token} is not an array.`);
} }
const [type, value] = token as [string, string]; const [type = '', value = ''] = token as [TokenType, string];
switch (type) { switch (type) {
case DIM: { case DIM: {
let resolvedValue;
if (format === VAL_SPEC && !mathFunc.has(nest)) { if (format === VAL_SPEC && !mathFunc.has(nest)) {
resolvedValue = value as string; res.push(value);
} else { } else {
resolvedValue = resolveDimension(token, opt) as string | null; const resolvedValue = resolveDimension(token, opt);
if (!resolvedValue) { if (isString(resolvedValue)) {
resolvedValue = value as string; res.push(resolvedValue);
} else {
res.push(value);
} }
} }
res.push(resolvedValue as string);
break; break;
} }
case FUNC: case FUNC:
case PAREN_OPEN: { case PAREN_OPEN: {
res.push(value); res.push(value);
nest++; nest++;
if (REG_START_MATH.test(value)) { if (REG_FN_MATH_START.test(value)) {
mathFunc.add(nest); mathFunc.add(nest);
} }
break; break;
} }
case PAREN_CLOSE: { case PAREN_CLOSE: {
if (res.length) { if (res.length) {
const lastValue = res[res.length - 1] as string; const lastValue = res[res.length - 1];
if (lastValue === ' ') { if (lastValue === ' ') {
res.splice(-1, 1, value); res.splice(-1, 1, value);
} else { } else {
@ -858,8 +862,12 @@ export const parseTokens = (
} }
case W_SPACE: { case W_SPACE: {
if (res.length) { if (res.length) {
const lastValue = res[res.length - 1] as string; const lastValue = res[res.length - 1];
if (!lastValue.endsWith('(') && lastValue !== ' ') { if (
isString(lastValue) &&
!lastValue.endsWith('(') &&
lastValue !== ' '
) {
res.push(value); res.push(value);
} }
} }
@ -876,81 +884,65 @@ export const parseTokens = (
}; };
/** /**
* resolve CSS calc() * CSS calc()
* @param {string} value - color value including calc() * @param value - CSS value including calc()
* @param {object} [opt] - options * @param [opt] - options
* @param {object} [opt.dimension] - dimension * @returns resolved value
* @param {string} [opt.format] - output format
* @returns {?string} - value
*/ */
export const cssCalc = ( export const cssCalc = (value: string, opt: Options = {}): string => {
value: string, const { format = '' } = opt;
opt: {
dimension?: object;
format?: string;
} = {}
): string | null => {
const { format, dimension = {} } = opt;
if (isString(value)) { if (isString(value)) {
if (REG_FN_VAR.test(value)) { if (REG_FN_VAR.test(value)) {
if (format === VAL_SPEC) { if (format === VAL_SPEC) {
return value; return value;
// var() must be resolved before cssCalc()
} else { } else {
throw new SyntaxError(`Unexpected token ${FN_VAR} found.`); const resolvedValue = resolveVar(value, opt);
if (isString(resolvedValue)) {
return resolvedValue;
} else {
return '';
}
} }
} else if (!REG_FN_MATH_CALC.test(value)) { } else if (!REG_FN_CALC.test(value)) {
return value; return value;
} }
value = value.toLowerCase().trim(); value = value.toLowerCase().trim();
} else { } else {
throw new TypeError(`${value} is not a string`); throw new TypeError(`${value} is not a string.`);
} }
let cacheKey; const cacheKey: string = createCacheKey(
if ( {
typeof ( namespace: NAMESPACE,
dimension as { name: 'cssCalc',
callback?: (unit: string) => number; value
} },
).callback !== 'function' opt
) { );
cacheKey = `{cssCalc:${value},opt:${valueToJsonString(opt)}}`; const cachedResult = getCache(cacheKey);
if (cachedResults.has(cacheKey)) { if (cachedResult instanceof CacheItem) {
return cachedResults.get(cacheKey) as string | null; return cachedResult.item as string;
}
} }
let resolvedValue; const tokens = tokenize({ css: value });
if (dimension) { const values = parseTokens(tokens, opt);
const tokens = tokenize({ css: value }); let resolvedValue: string = calc(values.join(''), {
const values = parseTokens(tokens, opt); toCanonicalUnits: true
resolvedValue = calc(values.join(''), { });
toCanonicalUnits: true if (REG_FN_VAR_START.test(value)) {
}) as string;
} else {
resolvedValue = calc(value, {
toCanonicalUnits: true
}) as string;
}
if (REG_START_MATH_VAR.test(value)) {
if (REG_TYPE_DIM_PCT.test(resolvedValue)) { if (REG_TYPE_DIM_PCT.test(resolvedValue)) {
const [, val, unit] = resolvedValue.match(REG_TYPE_DIM_PCT) as [ const [, val, unit] = resolvedValue.match(
string, REG_TYPE_DIM_PCT
string, ) as MatchedRegExp;
string
];
resolvedValue = `${roundToPrecision(Number(val), HEX)}${unit}`; resolvedValue = `${roundToPrecision(Number(val), HEX)}${unit}`;
} }
// wrap with `calc()` // wrap with `calc()`
if ( if (
resolvedValue && resolvedValue &&
!REG_START_MATH_VAR.test(resolvedValue as string) && !REG_FN_VAR_START.test(resolvedValue) &&
format === VAL_SPEC format === VAL_SPEC
) { ) {
resolvedValue = `calc(${resolvedValue})`; resolvedValue = `calc(${resolvedValue})`;
} }
} }
if (cacheKey) { setCache(cacheKey, resolvedValue);
cachedResults.set(cacheKey, resolvedValue);
}
return resolvedValue; return resolvedValue;
}; };

View File

@ -0,0 +1,287 @@
/**
* css-gradient
*/
import { CacheItem, createCacheKey, getCache, setCache } from './cache';
import { isString } from './common';
import { MatchedRegExp, Options } from './typedef';
import { isColor, splitValue } from './util';
/* constants */
import {
ANGLE,
CS_HUE,
CS_RECT,
LENGTH,
NUM,
NUM_POSITIVE,
PCT
} from './constant';
const NAMESPACE = 'css-gradient';
const DIM_ANGLE = `${NUM}(?:${ANGLE})`;
const DIM_ANGLE_PCT = `${DIM_ANGLE}|${PCT}`;
const DIM_LEN = `${NUM}(?:${LENGTH})|0`;
const DIM_LEN_PCT = `${DIM_LEN}|${PCT}`;
const DIM_LEN_PCT_POSI = `${NUM_POSITIVE}(?:${LENGTH}|%)|0`;
const DIM_LEN_POSI = `${NUM_POSITIVE}(?:${LENGTH})|0`;
const CTR = 'center';
const L_R = 'left|right';
const T_B = 'top|bottom';
const S_E = 'start|end';
const AXIS_X = `${L_R}|x-(?:${S_E})`;
const AXIS_Y = `${T_B}|y-(?:${S_E})`;
const BLOCK = `block-(?:${S_E})`;
const INLINE = `inline-(?:${S_E})`;
const POS_1 = `${CTR}|${AXIS_X}|${AXIS_Y}|${BLOCK}|${INLINE}|${DIM_LEN_PCT}`;
const POS_2 = [
`(?:${CTR}|${AXIS_X})\\s+(?:${CTR}|${AXIS_Y})`,
`(?:${CTR}|${AXIS_Y})\\s+(?:${CTR}|${AXIS_X})`,
`(?:${CTR}|${AXIS_X}|${DIM_LEN_PCT})\\s+(?:${CTR}|${AXIS_Y}|${DIM_LEN_PCT})`,
`(?:${CTR}|${BLOCK})\\s+(?:${CTR}|${INLINE})`,
`(?:${CTR}|${INLINE})\\s+(?:${CTR}|${BLOCK})`,
`(?:${CTR}|${S_E})\\s+(?:${CTR}|${S_E})`
].join('|');
const POS_4 = [
`(?:${AXIS_X})\\s+(?:${DIM_LEN_PCT})\\s+(?:${AXIS_Y})\\s+(?:${DIM_LEN_PCT})`,
`(?:${AXIS_Y})\\s+(?:${DIM_LEN_PCT})\\s+(?:${AXIS_X})\\s+(?:${DIM_LEN_PCT})`,
`(?:${BLOCK})\\s+(?:${DIM_LEN_PCT})\\s+(?:${INLINE})\\s+(?:${DIM_LEN_PCT})`,
`(?:${INLINE})\\s+(?:${DIM_LEN_PCT})\\s+(?:${BLOCK})\\s+(?:${DIM_LEN_PCT})`,
`(?:${S_E})\\s+(?:${DIM_LEN_PCT})\\s+(?:${S_E})\\s+(?:${DIM_LEN_PCT})`
].join('|');
const RAD_EXTENT = '(?:clos|farth)est-(?:corner|side)';
const RAD_SIZE = [
`${RAD_EXTENT}(?:\\s+${RAD_EXTENT})?`,
`${DIM_LEN_POSI}`,
`(?:${DIM_LEN_PCT_POSI})\\s+(?:${DIM_LEN_PCT_POSI})`
].join('|');
const RAD_SHAPE = 'circle|ellipse';
const FROM_ANGLE = `from\\s+${DIM_ANGLE}`;
const AT_POSITION = `at\\s+(?:${POS_1}|${POS_2}|${POS_4})`;
const TO_SIDE_CORNER = `to\\s+(?:(?:${L_R})(?:\\s(?:${T_B}))?|(?:${T_B})(?:\\s(?:${L_R}))?)`;
const IN_COLOR_SPACE = `in\\s+(?:${CS_RECT}|${CS_HUE})`;
/* type definitions */
/**
* @type ColorStopList - list of color stops
*/
type ColorStopList = [string, string, ...string[]];
/**
* @typedef Gradient - parsed CSS gradient
* @property value - input value
* @property type - gradient type
* @property [gradientLine] - gradient line
* @property colorStopList - list of color stops
*/
interface Gradient {
value: string;
type: string;
gradientLine?: string;
colorStopList: ColorStopList;
}
/* regexp */
const REG_GRAD = /^(?:repeating-)?(?:conic|linear|radial)-gradient\(/;
const REG_GRAD_CAPT = /^((?:repeating-)?(?:conic|linear|radial)-gradient)\(/;
/**
* get gradient type
* @param value - gradient value
* @returns gradient type
*/
export const getGradientType = (value: string): string => {
if (isString(value)) {
value = value.trim();
if (REG_GRAD.test(value)) {
const [, type] = value.match(REG_GRAD_CAPT) as MatchedRegExp;
return type;
}
}
return '';
};
/**
* validate gradient line
* @param value - gradient line value
* @param type - gradient type
* @returns result
*/
export const validateGradientLine = (value: string, type: string): boolean => {
if (isString(value) && isString(type)) {
value = value.trim();
type = type.trim();
let lineSyntax = '';
if (/^(?:repeating-)?linear-gradient$/.test(type)) {
/*
* <linear-gradient-line> = [
* [ <angle> | to <side-or-corner> ] ||
* <color-interpolation-method>
* ]
*/
lineSyntax = [
`(?:${DIM_ANGLE}|${TO_SIDE_CORNER})(?:\\s+${IN_COLOR_SPACE})?`,
`${IN_COLOR_SPACE}(?:\\s+(?:${DIM_ANGLE}|${TO_SIDE_CORNER}))?`
].join('|');
} else if (/^(?:repeating-)?radial-gradient$/.test(type)) {
/*
* <radial-gradient-line> = [
* [ [ <radial-shape> || <radial-size> ]? [ at <position> ]? ] ||
* <color-interpolation-method>]?
*/
lineSyntax = [
`(?:${RAD_SHAPE})(?:\\s+(?:${RAD_SIZE}))?(?:\\s+${AT_POSITION})?(?:\\s+${IN_COLOR_SPACE})?`,
`(?:${RAD_SIZE})(?:\\s+(?:${RAD_SHAPE}))?(?:\\s+${AT_POSITION})?(?:\\s+${IN_COLOR_SPACE})?`,
`${AT_POSITION}(?:\\s+${IN_COLOR_SPACE})?`,
`${IN_COLOR_SPACE}(?:\\s+${RAD_SHAPE})(?:\\s+(?:${RAD_SIZE}))?(?:\\s+${AT_POSITION})?`,
`${IN_COLOR_SPACE}(?:\\s+${RAD_SIZE})(?:\\s+(?:${RAD_SHAPE}))?(?:\\s+${AT_POSITION})?`,
`${IN_COLOR_SPACE}(?:\\s+${AT_POSITION})?`
].join('|');
} else if (/^(?:repeating-)?conic-gradient$/.test(type)) {
/*
* <conic-gradient-line> = [
* [ [ from <angle> ]? [ at <position> ]? ] ||
* <color-interpolation-method>
* ]
*/
lineSyntax = [
`${FROM_ANGLE}(?:\\s+${AT_POSITION})?(?:\\s+${IN_COLOR_SPACE})?`,
`${AT_POSITION}(?:\\s+${IN_COLOR_SPACE})?`,
`${IN_COLOR_SPACE}(?:\\s+${FROM_ANGLE})?(?:\\s+${AT_POSITION})?`
].join('|');
}
if (lineSyntax) {
const reg = new RegExp(`^(?:${lineSyntax})$`);
return reg.test(value);
}
}
return false;
};
/**
* validate color stop list
* @param list
* @param type
* @param [opt]
* @returns result
*/
export const validateColorStopList = (
list: string[],
type: string,
opt: Options = {}
): boolean => {
if (Array.isArray(list) && list.length > 1) {
const dimension = /^(?:repeating-)?conic-gradient$/.test(type)
? DIM_ANGLE_PCT
: DIM_LEN_PCT;
const regColorHint = new RegExp(`^(?:${dimension})$`);
const regDimension = new RegExp(`(?:\\s+(?:${dimension})){1,2}$`);
const arr = [];
for (const item of list) {
if (isString(item)) {
if (regColorHint.test(item)) {
arr.push('hint');
} else {
const color = item.replace(regDimension, '');
if (isColor(color, opt)) {
arr.push('color');
} else {
return false;
}
}
}
}
const value = arr.join(',');
return /^color(?:,(?:hint,)?color)+$/.test(value);
}
return false;
};
/**
* parse CSS gradient
* @param value - gradient value
* @param [opt] - options
* @returns parsed result
*/
export const parseGradient = (
value: string,
opt: Options = {}
): Gradient | null => {
if (isString(value)) {
value = value.trim();
const cacheKey: string = createCacheKey(
{
namespace: NAMESPACE,
name: 'parseGradient',
value
},
opt
);
const cachedResult = getCache(cacheKey);
if (cachedResult instanceof CacheItem) {
if (cachedResult.isNull) {
return null;
}
return cachedResult.item as Gradient;
}
const type = getGradientType(value);
const gradValue = value.replace(REG_GRAD, '').replace(/\)$/, '');
if (type && gradValue) {
const [lineOrColorStop = '', ...colorStops] = splitValue(gradValue, ',');
const dimension = /^(?:repeating-)?conic-gradient$/.test(type)
? DIM_ANGLE_PCT
: DIM_LEN_PCT;
const regDimension = new RegExp(`(?:\\s+(?:${dimension})){1,2}$`);
let isColorStop = false;
if (regDimension.test(lineOrColorStop)) {
const colorStop = lineOrColorStop.replace(regDimension, '');
if (isColor(colorStop, opt)) {
isColorStop = true;
}
} else if (isColor(lineOrColorStop, opt)) {
isColorStop = true;
}
if (isColorStop) {
colorStops.unshift(lineOrColorStop);
const valid = validateColorStopList(colorStops, type, opt);
if (valid) {
const res: Gradient = {
value,
type,
colorStopList: colorStops as ColorStopList
};
setCache(cacheKey, res);
return res;
}
} else if (colorStops.length > 1) {
const gradientLine = lineOrColorStop;
const valid =
validateGradientLine(gradientLine, type) &&
validateColorStopList(colorStops, type, opt);
if (valid) {
const res: Gradient = {
value,
type,
gradientLine,
colorStopList: colorStops as ColorStopList
};
setCache(cacheKey, res);
return res;
}
}
}
setCache(cacheKey, null);
return null;
}
return null;
};
/**
* is CSS gradient
* @param value - CSS value
* @param [opt] - options
* @returns result
*/
export const isGradient = (value: string, opt: Options = {}): boolean => {
const gradient = parseGradient(value, opt);
return gradient !== null;
};

View File

@ -1,18 +1,22 @@
/** /**
* css-var.js * css-var
*/ */
import { TokenType, tokenize } from '@csstools/css-tokenizer'; import { CSSToken, TokenType, tokenize } from '@csstools/css-tokenizer';
import { LRUCache } from 'lru-cache'; import {
CacheItem,
NullObject,
createCacheKey,
getCache,
setCache
} from './cache';
import { isString } from './common'; import { isString } from './common';
import { cssCalc } from './css-calc'; import { cssCalc } from './css-calc';
import { isColor, valueToJsonString } from './util'; import { isColor } from './util';
import { Options } from './typedef';
/* types */
import type { CSSToken } from '@csstools/css-tokenizer';
/* constants */ /* constants */
import { FN_VAR, SYN_FN_MATH_CALC, SYN_FN_VAR, VAL_SPEC } from './constant'; import { FN_VAR, SYN_FN_CALC, SYN_FN_VAR, VAL_SPEC } from './constant';
const { const {
CloseParen: PAREN_CLOSE, CloseParen: PAREN_CLOSE,
Comment: COMMENT, Comment: COMMENT,
@ -20,99 +24,82 @@ const {
Ident: IDENT, Ident: IDENT,
Whitespace: W_SPACE Whitespace: W_SPACE
} = TokenType; } = TokenType;
const NAMESPACE = 'css-var';
/* regexp */ /* regexp */
const REG_FN_MATH_CALC = new RegExp(SYN_FN_MATH_CALC); const REG_FN_CALC = new RegExp(SYN_FN_CALC);
const REG_FN_VAR = new RegExp(SYN_FN_VAR); const REG_FN_VAR = new RegExp(SYN_FN_VAR);
/* cached results */
export const cachedResults = new LRUCache({
max: 4096
});
/** /**
* resolve custom property * resolve custom property
* @param {Array.<Array>} tokens - tokens * @param tokens - CSS tokens
* @param {object} [opt] - options * @param [opt] - options
* @param {object} [opt.customProperty] - custom properties * @returns result - [tokens, resolvedValue]
* @returns {Array.<string|Array|undefined>} - [tokens, resolvedValue]
*/ */
export function resolveCustomProperty( export function resolveCustomProperty(
tokens: Array<CSSToken>, tokens: CSSToken[],
opt: { opt: Options = {}
customProperty?: object; ): [CSSToken[], string] {
dimension?: object;
format?: string;
} = {}
): Array<string | Array<CSSToken> | undefined> {
if (!Array.isArray(tokens)) { if (!Array.isArray(tokens)) {
throw new TypeError(`${tokens} is not an array.`); throw new TypeError(`${tokens} is not an array.`);
} }
const { customProperty = {} } = opt; const { customProperty = {} } = opt;
const items = []; const items: string[] = [];
while (tokens.length) { while (tokens.length) {
const token = tokens.shift(); const token = tokens.shift();
if (!Array.isArray(token)) { if (!Array.isArray(token)) {
throw new TypeError(`${token} is not an array.`); throw new TypeError(`${token} is not an array.`);
} }
const [type, value] = token as [string, string]; const [type, value] = token as [TokenType, string];
// end of var() // end of var()
if (type === PAREN_CLOSE) { if (type === PAREN_CLOSE) {
break; break;
} }
// nested var() // nested var()
if (value === FN_VAR) { if (value === FN_VAR) {
const [restTokens, item] = resolveCustomProperty(tokens, opt) as [ const [restTokens, item] = resolveCustomProperty(tokens, opt);
Array<CSSToken>,
string
];
tokens = restTokens; tokens = restTokens;
if (item) { if (item) {
items.push(item); items.push(item);
} }
} else if (type === IDENT) { } else if (type === IDENT) {
if (value.startsWith('--')) { if (value.startsWith('--')) {
let item;
if (Object.hasOwnProperty.call(customProperty, value)) { if (Object.hasOwnProperty.call(customProperty, value)) {
items.push(customProperty[value as never]); item = customProperty[value] as string;
} else if ( } else if (typeof customProperty.callback === 'function') {
typeof ( item = customProperty.callback(value);
customProperty as { callback?: (value: string) => string } }
).callback === 'function' if (item) {
) { items.push(item);
const item = (
customProperty as { callback: (value: string) => string }
).callback(value);
if (item) {
items.push(item);
}
} }
} else if (value) { } else if (value) {
items.push(value); items.push(value);
} }
} }
} }
let resolveAsColor; let resolveAsColor = false;
if (items.length > 1) { if (items.length > 1) {
const lastValue = items[items.length - 1]; const lastValue = items[items.length - 1];
resolveAsColor = isColor(lastValue as string) as boolean; resolveAsColor = isColor(lastValue);
} }
let resolvedValue; let resolvedValue = '';
for (let item of items) { for (let item of items) {
item = item.trim() as string; item = item.trim();
if (REG_FN_VAR.test(item)) { if (REG_FN_VAR.test(item)) {
// recurse cssVar() // recurse resolveVar()
item = cssVar(item, opt) as string; const resolvedItem = resolveVar(item, opt);
if (item) { if (isString(resolvedItem)) {
if (resolveAsColor) { if (resolveAsColor) {
if (isColor(item)) { if (isColor(resolvedItem)) {
resolvedValue = item; resolvedValue = resolvedItem;
} }
} else { } else {
resolvedValue = item; resolvedValue = resolvedItem;
} }
} }
} else if (REG_FN_MATH_CALC.test(item)) { } else if (REG_FN_CALC.test(item)) {
item = cssCalc(item as string, opt) as string; item = cssCalc(item, opt);
if (resolveAsColor) { if (resolveAsColor) {
if (isColor(item)) { if (isColor(item)) {
resolvedValue = item; resolvedValue = item;
@ -141,25 +128,25 @@ export function resolveCustomProperty(
/** /**
* parse tokens * parse tokens
* @param {Array.<Array>} tokens - tokens * @param tokens - CSS tokens
* @param {object} [opt] - options * @param [opt] - options
* @returns {?Array.<string>} - parsed tokens * @returns parsed tokens
*/ */
export function parseTokens( export function parseTokens(
tokens: Array<CSSToken>, tokens: CSSToken[],
opt: object = {} opt: Options = {}
): Array<string> | null { ): string[] | NullObject {
const res = [] as string[]; const res: string[] = [];
while (tokens.length) { while (tokens.length) {
const token = tokens.shift(); const token = tokens.shift();
const [type, value] = token as [string, string]; const [type = '', value = ''] = token as [TokenType, string];
if (value === FN_VAR) { if (value === FN_VAR) {
const [restTokens, resolvedValue] = resolveCustomProperty(tokens, opt); const [restTokens, resolvedValue] = resolveCustomProperty(tokens, opt);
if (!resolvedValue) { if (!resolvedValue) {
return null; return new NullObject();
} }
tokens = restTokens as Array<CSSToken>; tokens = restTokens;
res.push(resolvedValue as string); res.push(resolvedValue);
} else { } else {
switch (type) { switch (type) {
case PAREN_CLOSE: { case PAREN_CLOSE: {
@ -177,8 +164,12 @@ export function parseTokens(
} }
case W_SPACE: { case W_SPACE: {
if (res.length) { if (res.length) {
const lastValue = res[res.length - 1] as string; const lastValue = res[res.length - 1];
if (!lastValue.endsWith('(') && lastValue !== ' ') { if (
isString(lastValue) &&
!lastValue.endsWith('(') &&
lastValue !== ' '
) {
res.push(value); res.push(value);
} }
} }
@ -197,19 +188,15 @@ export function parseTokens(
/** /**
* resolve CSS var() * resolve CSS var()
* @param {string} value - color value including var() * @param value - CSS value including var()
* @param {object} [opt] - options * @param [opt] - options
* @param {object} [opt.customProperty] - custom properties * @returns resolved value
* @returns {?string} - value
*/ */
export function cssVar( export function resolveVar(
value: string, value: string,
opt: { opt: Options = {}
customProperty?: object; ): string | NullObject {
format?: string; const { format = '' } = opt;
} = {}
): string | null {
const { customProperty = {}, format } = opt;
if (isString(value)) { if (isString(value)) {
if (!REG_FN_VAR.test(value) || format === VAL_SPEC) { if (!REG_FN_VAR.test(value) || format === VAL_SPEC) {
return value; return value;
@ -218,32 +205,46 @@ export function cssVar(
} else { } else {
throw new TypeError(`${value} is not a string.`); throw new TypeError(`${value} is not a string.`);
} }
let cacheKey; const cacheKey: string = createCacheKey(
if ( {
typeof ( namespace: NAMESPACE,
customProperty as { callback?: (value: string) => string } name: 'resolveVar',
).callback !== 'function' value
) { },
cacheKey = `{cssVar:${value},opt:${valueToJsonString(opt)}}`; opt
if (cachedResults.has(cacheKey)) { );
return cachedResults.get(cacheKey) as string | null; const cachedResult = getCache(cacheKey);
if (cachedResult instanceof CacheItem) {
if (cachedResult.isNull) {
return cachedResult as NullObject;
} }
return cachedResult.item as string;
} }
const tokens = tokenize({ css: value }); const tokens = tokenize({ css: value });
const values = parseTokens(tokens, opt); const values = parseTokens(tokens, opt);
if (Array.isArray(values)) { if (Array.isArray(values)) {
let color = values.join('') as string | null; let color = values.join('');
if (REG_FN_MATH_CALC.test(color as string)) { if (REG_FN_CALC.test(color)) {
color = cssCalc(color as string, opt) as string | null; color = cssCalc(color, opt);
}
if (cacheKey) {
cachedResults.set(cacheKey as string, color!);
} }
setCache(cacheKey, color);
return color; return color;
} else { } else {
if (cacheKey) { setCache(cacheKey, null);
cachedResults.set(cacheKey, null!); return new NullObject();
}
return null;
} }
} }
/**
* CSS var()
* @param value - CSS value including var()
* @param [opt] - options
* @returns resolved value
*/
export const cssVar = (value: string, opt: Options = {}): string => {
const resolvedValue = resolveVar(value, opt);
if (isString(resolvedValue)) {
return resolvedValue;
}
return '';
};

View File

@ -1,20 +1,31 @@
/** /**
* relative-color.js * relative-color
*/ */
import { SyntaxFlag, color as colorParser } from '@csstools/css-color-parser'; import { SyntaxFlag, color as colorParser } from '@csstools/css-color-parser';
import { parseComponentValue } from '@csstools/css-parser-algorithms'; import {
import { TokenType, tokenize } from '@csstools/css-tokenizer'; ComponentValue,
import { LRUCache } from 'lru-cache'; parseComponentValue
import { isString } from './common'; } from '@csstools/css-parser-algorithms';
import { colorToRgb } from './convert'; import { CSSToken, TokenType, tokenize } from '@csstools/css-tokenizer';
import {
CacheItem,
NullObject,
createCacheKey,
getCache,
setCache
} from './cache';
import { NAMED_COLORS, convertColorToRgb } from './color';
import { isString, isStringOrNumber } from './common';
import { resolveDimension, serializeCalc } from './css-calc'; import { resolveDimension, serializeCalc } from './css-calc';
import { resolve } from './resolve'; import { resolveColor } from './resolve';
import { roundToPrecision, valueToJsonString } from './util'; import { roundToPrecision } from './util';
import {
/* types */ ColorChannels,
import type { ComponentValue } from '@csstools/css-parser-algorithms'; MatchedRegExp,
import type { CSSToken } from '@csstools/css-tokenizer'; Options,
StringColorChannels
} from './typedef';
/* constants */ /* constants */
import { import {
@ -25,12 +36,11 @@ import {
FN_VAR, FN_VAR,
NONE, NONE,
SYN_COLOR_TYPE, SYN_COLOR_TYPE,
SYN_FN_MATH, SYN_FN_MATH_START,
SYN_FN_VAR, SYN_FN_VAR,
SYN_MIX, SYN_MIX,
VAL_SPEC VAL_SPEC
} from './constant'; } from './constant';
import { NAMED_COLORS } from './color';
const { const {
CloseParen: PAREN_CLOSE, CloseParen: PAREN_CLOSE,
Comment: COMMENT, Comment: COMMENT,
@ -43,52 +53,48 @@ const {
Percentage: PCT, Percentage: PCT,
Whitespace: W_SPACE Whitespace: W_SPACE
} = TokenType; } = TokenType;
const { const { HasNoneKeywords: KEY_NONE } = SyntaxFlag;
HasNoneKeywords: NONE_KEY const NAMESPACE = 'relative-color';
} = SyntaxFlag;
/* numeric constants */
const OCT = 8; const OCT = 8;
const DEC = 10; const DEC = 10;
const HEX = 16; const HEX = 16;
const MAX_PCT = 100; const MAX_PCT = 100;
const MAX_RGB = 255; const MAX_RGB = 255;
/* type definitions */
/**
* @type NumberOrStringColorChannels - color channel
*/
type NumberOrStringColorChannels = ColorChannels & StringColorChannels;
/* regexp */ /* regexp */
const REG_COLOR_CAPT = new RegExp( const REG_COLOR_CAPT = new RegExp(
`^${FN_REL}(${SYN_COLOR_TYPE}|${SYN_MIX})\\s+` `^${FN_REL}(${SYN_COLOR_TYPE}|${SYN_MIX})\\s+`
); );
const REG_CS_HSL = /(?:hsla?|hwb)$/; const REG_CS_HSL = /(?:hsla?|hwb)$/;
const REG_CS_CIE = new RegExp(`^(?:${CS_LAB}|${CS_LCH})$`); const REG_CS_CIE = new RegExp(`^(?:${CS_LAB}|${CS_LCH})$`);
const REG_FN_MATH_START = new RegExp(SYN_FN_MATH_START);
const REG_FN_REL = new RegExp(FN_REL);
const REG_FN_REL_CAPT = new RegExp(`^${FN_REL_CAPT}`);
const REG_FN_REL_START = new RegExp(`^${FN_REL}`);
const REG_FN_VAR = new RegExp(SYN_FN_VAR); const REG_FN_VAR = new RegExp(SYN_FN_VAR);
const REG_REL = new RegExp(FN_REL);
const REG_REL_CAPT = new RegExp(`^${FN_REL_CAPT}`);
const REG_START_MATH = new RegExp(SYN_FN_MATH);
const REG_START_REL = new RegExp(`^${FN_REL}`);
/* cached results */
export const cachedResults = new LRUCache({
max: 4096
});
/** /**
* resolve relative color channels * resolve relative color channels
* @param {Array.<Array>} tokens - tokens * @param tokens - CSS tokens
* @param {object} [opt] - options * @param [opt] - options
* @param {string} [opt.colorSpace] - color space * @returns resolved color channels
* @returns {?Array.<string>} - resolved channels
*/ */
export function resolveColorChannels( export function resolveColorChannels(
tokens: Array<CSSToken>, tokens: CSSToken[],
opt: { opt: Options = {}
colorSpace?: string; ): NumberOrStringColorChannels | NullObject {
currentColor?: string;
dimension?: object;
format?: string;
} = {}
): Array<string> | null {
if (!Array.isArray(tokens)) { if (!Array.isArray(tokens)) {
throw new TypeError(`${tokens} is not an array.`); throw new TypeError(`${tokens} is not an array.`);
} }
const { colorSpace, format } = opt; const { colorSpace = '', format = '' } = opt;
const colorChannels = new Map([ const colorChannels = new Map([
['color', ['r', 'g', 'b', 'alpha']], ['color', ['r', 'g', 'b', 'alpha']],
['hsl', ['h', 's', 'l', 'alpha']], ['hsl', ['h', 's', 'l', 'alpha']],
@ -101,9 +107,18 @@ export function resolveColorChannels(
['rgb', ['r', 'g', 'b', 'alpha']], ['rgb', ['r', 'g', 'b', 'alpha']],
['rgba', ['r', 'g', 'b', 'alpha']] ['rgba', ['r', 'g', 'b', 'alpha']]
]); ]);
const colorChannel = colorChannels.get(colorSpace as string); const colorChannel = colorChannels.get(colorSpace);
// invalid color channel
if (!colorChannel) {
return new NullObject();
}
const mathFunc = new Set(); const mathFunc = new Set();
const channels = [[], [], [], []] as Array<Array<string | number>>; const channels: [
(number | string)[],
(number | string)[],
(number | string)[],
(number | string)[]
] = [[], [], [], []];
let i = 0; let i = 0;
let nest = 0; let nest = 0;
let func = false; let func = false;
@ -112,99 +127,103 @@ export function resolveColorChannels(
if (!Array.isArray(token)) { if (!Array.isArray(token)) {
throw new TypeError(`${token} is not an array.`); throw new TypeError(`${token} is not an array.`);
} }
const [type, value, , , detail = {}] = token; const [type, value, , , detail] = token as [
const numValue = (detail as { TokenType,
value?: number; string,
})?.value as number | undefined; number,
const channel = channels[i]!; number,
switch (type as string) { { value: string | number } | undefined
case DIM: { ];
let resolvedValue = resolveDimension(token, opt) as string | null; const channel = channels[i];
if (!resolvedValue) { if (Array.isArray(channel)) {
resolvedValue = value as string; switch (type) {
} case DIM: {
channel.push(resolvedValue as string); const resolvedValue = resolveDimension(token, opt);
break; if (isString(resolvedValue)) {
} channel.push(resolvedValue);
case FUNC: {
channel.push(value);
func = true;
nest++;
if (REG_START_MATH.test(value)) {
mathFunc.add(nest);
}
break;
}
case IDENT: {
// invalid channel key
if (!colorChannel || !colorChannel.includes(value)) {
return null;
}
channel.push(value);
if (!func) {
i++;
}
break;
}
case NUM: {
const n = numValue ?? parseFloat(value);
channel.push(n);
if (!func) {
i++;
}
break;
}
case PAREN_OPEN: {
channel.push(value);
nest++;
break;
}
case PAREN_CLOSE: {
if (func) {
const lastValue = channel[channel.length - 1] as string | number;
if (lastValue === ' ') {
channel.splice(-1, 1, value);
} else { } else {
channel.push(value); channel.push(value);
} }
if (mathFunc.has(nest)) { break;
mathFunc.delete(nest); }
case FUNC: {
channel.push(value);
func = true;
nest++;
if (REG_FN_MATH_START.test(value)) {
mathFunc.add(nest);
} }
nest--; break;
if (nest === 0) { }
func = false; case IDENT: {
// invalid channel key
if (!colorChannel.includes(value)) {
return new NullObject();
}
channel.push(value);
if (!func) {
i++; i++;
} }
break;
} }
break; case NUM: {
} channel.push(Number(detail?.value));
case PCT: { if (!func) {
const n = numValue ?? parseFloat(value); i++;
channel.push(n / MAX_PCT); }
if (!func) { break;
i++;
} }
break; case PAREN_OPEN: {
} channel.push(value);
case W_SPACE: { nest++;
if (channel.length && func) { break;
const lastValue = channel[channel.length - 1] as string | number; }
if (typeof lastValue === 'number') { case PAREN_CLOSE: {
channel.push(value); if (func) {
} else if ( const lastValue = channel[channel.length - 1];
isString(lastValue) && if (lastValue === ' ') {
!lastValue.endsWith('(') && channel.splice(-1, 1, value);
lastValue !== ' ' } else {
) { channel.push(value);
}
if (mathFunc.has(nest)) {
mathFunc.delete(nest);
}
nest--;
if (nest === 0) {
func = false;
i++;
}
}
break;
}
case PCT: {
channel.push(Number(detail?.value) / MAX_PCT);
if (!func) {
i++;
}
break;
}
case W_SPACE: {
if (channel.length && func) {
const lastValue = channel[channel.length - 1];
if (typeof lastValue === 'number') {
channel.push(value);
} else if (
isString(lastValue) &&
!lastValue.endsWith('(') &&
lastValue !== ' '
) {
channel.push(value);
}
}
break;
}
default: {
if (type !== COMMENT && type !== EOF && func) {
channel.push(value); channel.push(value);
} }
} }
break;
}
default: {
if (type !== COMMENT && type !== EOF && func) {
channel.push(value);
}
} }
} }
} }
@ -212,215 +231,187 @@ export function resolveColorChannels(
for (const channel of channels) { for (const channel of channels) {
if (channel.length === 1) { if (channel.length === 1) {
const [resolvedValue] = channel; const [resolvedValue] = channel;
channelValues.push(resolvedValue as string); if (isStringOrNumber(resolvedValue)) {
channelValues.push(resolvedValue);
}
} else if (channel.length) { } else if (channel.length) {
const resolvedValue = serializeCalc(channel.join(''), { const resolvedValue = serializeCalc(channel.join(''), {
format format
}); });
if (resolvedValue) { channelValues.push(resolvedValue);
channelValues.push(resolvedValue);
} else {
return null;
}
} }
} }
return channelValues; return channelValues as NumberOrStringColorChannels;
} }
/** /**
* extract origin color * extract origin color
* @param {string} value - color value * @param value - CSS color value
* @param {object} [opt] - options * @param [opt] - options
* @param {string} [opt.currentColor] - current color value * @returns origin color value
* @returns {?string} - value
*/ */
export function extractOriginColor( export function extractOriginColor(
value: string, value: string,
opt: { opt: Options = {}
colorSpace?: string; ): string | NullObject {
currentColor?: string; const { currentColor = '', format = '' } = opt;
dimension?: object;
format?: string;
} = {}
): string | null {
if (isString(value)) { if (isString(value)) {
value = value.toLowerCase().trim(); value = value.toLowerCase().trim();
if (!value) { if (!value) {
return null; return new NullObject();
} }
if (!REG_START_REL.test(value)) { if (!REG_FN_REL_START.test(value)) {
return value; return value;
} }
} else { } else {
return null; return new NullObject();
} }
const { currentColor, format } = opt; const cacheKey: string = createCacheKey(
const cacheKey = `{preProcess:${value},opt:${valueToJsonString(opt)}}`; {
if (cachedResults.has(cacheKey)) { namespace: NAMESPACE,
return cachedResults.get(cacheKey) as string | null; name: 'extractOriginColor',
value
},
opt
);
const cachedResult = getCache(cacheKey);
if (cachedResult instanceof CacheItem) {
if (cachedResult.isNull) {
return cachedResult as NullObject;
}
return cachedResult.item as string;
} }
if (/currentcolor/.test(value)) { if (/currentcolor/.test(value)) {
if (currentColor) { if (currentColor) {
value = value.replace(/currentcolor/g, currentColor); value = value.replace(/currentcolor/g, currentColor);
} else { } else {
if (cacheKey) { setCache(cacheKey, null);
cachedResults.set(cacheKey, null!); return new NullObject();
}
return null;
} }
} }
const cs = value.match(REG_REL_CAPT); let colorSpace = '';
let colorSpace: string; if (REG_FN_REL_CAPT.test(value)) {
if (cs) { [, colorSpace] = value.match(REG_FN_REL_CAPT) as MatchedRegExp;
[, colorSpace] = cs as [string, string];
} else {
return null;
} }
opt.colorSpace = colorSpace; opt.colorSpace = colorSpace;
if (REG_COLOR_CAPT.test(value)) { if (REG_COLOR_CAPT.test(value)) {
const [, originColor] = value.match(REG_COLOR_CAPT) as [string, string]; const [, originColor] = value.match(REG_COLOR_CAPT) as MatchedRegExp;
const [, restValue] = value.split(originColor); const [, restValue] = value.split(originColor) as MatchedRegExp;
if (/^[a-z]+$/.test(originColor)) { if (/^[a-z]+$/.test(originColor)) {
if ( if (
!/^transparent$/.test(originColor) && !/^transparent$/.test(originColor) &&
!Object.prototype.hasOwnProperty.call(NAMED_COLORS, originColor) !Object.prototype.hasOwnProperty.call(NAMED_COLORS, originColor)
) { ) {
if (cacheKey) { setCache(cacheKey, null);
cachedResults.set(cacheKey, null!); return new NullObject();
}
return null;
} }
} else if (format === VAL_SPEC) { } else if (format === VAL_SPEC) {
const resolvedOriginColor = resolve(originColor, opt) as string; const resolvedOriginColor = resolveColor(originColor, opt);
value = value.replace(originColor, resolvedOriginColor); if (isString(resolvedOriginColor)) {
value = value.replace(originColor, resolvedOriginColor);
}
} }
if (format === VAL_SPEC) { if (format === VAL_SPEC) {
const tokens = tokenize({ css: restValue as string }); const tokens = tokenize({ css: restValue });
const channelValues = const channelValues = resolveColorChannels(tokens, opt);
resolveColorChannels(tokens, opt) as Array<string> | null; if (channelValues instanceof NullObject) {
if (!Array.isArray(channelValues)) { setCache(cacheKey, null);
if (cacheKey) { return channelValues;
cachedResults.set(cacheKey, null!);
}
return null;
} }
let channelValue; const [v1, v2, v3, v4] = channelValues;
if (channelValues.length === 3) { let channelValue = '';
channelValue = ` ${channelValues.join(' ')})`; if (isStringOrNumber(v4)) {
} else {
const [v1, v2, v3, v4] = channelValues as [
string,
string,
string,
string
];
channelValue = ` ${v1} ${v2} ${v3} / ${v4})`; channelValue = ` ${v1} ${v2} ${v3} / ${v4})`;
} else {
channelValue = ` ${channelValues.join(' ')})`;
}
if (restValue !== channelValue) {
value = value.replace(restValue, channelValue);
} }
value = value.replace(restValue!, channelValue);
} }
// nested relative color // nested relative color
} else { } else {
const [, restValue] = value.split(REG_START_REL) as [ const [, restValue] = value.split(REG_FN_REL_START) as MatchedRegExp;
string, const tokens = tokenize({ css: restValue });
string const originColor: string[] = [];
]; let nest = 0;
if (REG_START_REL.test(restValue)) { while (tokens.length) {
const tokens = tokenize({ css: restValue }); const [type, tokenValue] = tokens.shift() as [TokenType, string];
const originColor = [] as Array<string>; switch (type) {
let nest = 0; case FUNC:
while (tokens.length) { case PAREN_OPEN: {
const token = tokens.shift(); originColor.push(tokenValue);
const [type, tokenValue] = token as [TokenType, string]; nest++;
switch (type) {
case FUNC:
case PAREN_OPEN: {
originColor.push(tokenValue);
nest++;
break;
}
case PAREN_CLOSE: {
const lastValue = originColor[originColor.length - 1] as string;
if (lastValue === ' ') {
originColor.splice(-1, 1, tokenValue);
} else {
originColor.push(tokenValue);
}
nest--;
break;
}
case W_SPACE: {
const lastValue = originColor[originColor.length - 1] as string;
if (!lastValue.endsWith('(') && lastValue !== ' ') {
originColor.push(tokenValue);
}
break;
}
default: {
if (type !== COMMENT && type !== EOF) {
originColor.push(tokenValue);
}
}
}
if (nest === 0) {
break; break;
} }
} case PAREN_CLOSE: {
const resolvedOriginColor = resolveRelativeColor( const lastValue = originColor[originColor.length - 1];
originColor.join('').trim(), if (lastValue === ' ') {
opt originColor.splice(-1, 1, tokenValue);
) as string | null; } else if (isString(lastValue)) {
if (!resolvedOriginColor) { originColor.push(tokenValue);
if (cacheKey) { }
cachedResults.set(cacheKey, null!); nest--;
break;
} }
return null; case W_SPACE: {
} const lastValue = originColor[originColor.length - 1];
const channelValues = if (
resolveColorChannels(tokens, opt) as Array<string> | null; isString(lastValue) &&
if (!Array.isArray(channelValues)) { !lastValue.endsWith('(') &&
if (cacheKey) { lastValue !== ' '
cachedResults.set(cacheKey, null!); ) {
originColor.push(tokenValue);
}
break;
}
default: {
if (type !== COMMENT && type !== EOF) {
originColor.push(tokenValue);
}
} }
return null;
} }
let channelValue; if (nest === 0) {
if (channelValues.length === 3) { break;
channelValue = ` ${channelValues.join(' ')})`;
} else {
const [v1, v2, v3, v4] = channelValues as [
string,
string,
string,
string
];
channelValue = ` ${v1} ${v2} ${v3} / ${v4})`;
} }
value = value.replace(restValue, `${resolvedOriginColor}${channelValue}`);
} }
const resolvedOriginColor = resolveRelativeColor(
originColor.join('').trim(),
opt
);
if (resolvedOriginColor instanceof NullObject) {
setCache(cacheKey, null);
return resolvedOriginColor;
}
const channelValues = resolveColorChannels(tokens, opt);
if (channelValues instanceof NullObject) {
setCache(cacheKey, null);
return channelValues;
}
const [v1, v2, v3, v4] = channelValues;
let channelValue = '';
if (isStringOrNumber(v4)) {
channelValue = ` ${v1} ${v2} ${v3} / ${v4})`;
} else {
channelValue = ` ${channelValues.join(' ')})`;
}
value = value.replace(restValue, `${resolvedOriginColor}${channelValue}`);
} }
if (cacheKey) { setCache(cacheKey, value);
cachedResults.set(cacheKey, value);
}
return value; return value;
} }
/** /**
* resolve relative color * resolve relative color
* @param {string} value - relative color value * @param value - CSS relative color value
* @param {object} [opt] - options * @param [opt] - options
* @param {string} [opt.format] - output format * @returns resolved value
* @returns {?string} - value
*/ */
export function resolveRelativeColor( export function resolveRelativeColor(
value: string, value: string,
opt: { opt: Options = {}
colorSpace?: string; ): string | NullObject {
currentColor?: string; const { format = '' } = opt;
dimension?: object;
format?: string;
} = {}
): string | null {
const { format } = opt;
if (isString(value)) { if (isString(value)) {
if (REG_FN_VAR.test(value)) { if (REG_FN_VAR.test(value)) {
if (format === VAL_SPEC) { if (format === VAL_SPEC) {
@ -429,26 +420,34 @@ export function resolveRelativeColor(
} else { } else {
throw new SyntaxError(`Unexpected token ${FN_VAR} found.`); throw new SyntaxError(`Unexpected token ${FN_VAR} found.`);
} }
} else if (!REG_REL.test(value)) { } else if (!REG_FN_REL.test(value)) {
return value; return value;
} }
value = value.toLowerCase().trim(); value = value.toLowerCase().trim();
} else { } else {
throw new TypeError(`${value} is not a string`); throw new TypeError(`${value} is not a string.`);
} }
const cacheKey = `{relativeColor:${value},opt:${valueToJsonString(opt)}}`; const cacheKey: string = createCacheKey(
if (cachedResults.has(cacheKey)) { {
return cachedResults.get(cacheKey) as string | null; namespace: NAMESPACE,
name: 'resolveRelativeColor',
value
},
opt
);
const cachedResult = getCache(cacheKey);
if (cachedResult instanceof CacheItem) {
if (cachedResult.isNull) {
return cachedResult as NullObject;
}
return cachedResult.item as string;
} }
const originColor = extractOriginColor(value, opt); const originColor = extractOriginColor(value, opt);
if (originColor) { if (originColor instanceof NullObject) {
value = originColor; setCache(cacheKey, null);
} else { return originColor;
if (cacheKey) {
cachedResults.set(cacheKey, null!);
}
return null;
} }
value = originColor;
if (format === VAL_SPEC) { if (format === VAL_SPEC) {
if (value.startsWith('rgba(')) { if (value.startsWith('rgba(')) {
value = value.replace(/^rgba\(/, 'rgb('); value = value.replace(/^rgba\(/, 'rgb(');
@ -458,13 +457,11 @@ export function resolveRelativeColor(
return value; return value;
} }
const tokens = tokenize({ css: value }); const tokens = tokenize({ css: value });
const components = parseComponentValue(tokens); const components = parseComponentValue(tokens) as ComponentValue;
const parsedComponents = colorParser(components as ComponentValue); const parsedComponents = colorParser(components);
if (!parsedComponents) { if (!parsedComponents) {
if (cacheKey) { setCache(cacheKey, null);
cachedResults.set(cacheKey, null!); return new NullObject();
}
return null;
} }
const { const {
alpha: alphaComponent, alpha: alphaComponent,
@ -474,13 +471,13 @@ export function resolveRelativeColor(
} = parsedComponents; } = parsedComponents;
let alpha: number | string; let alpha: number | string;
if (Number.isNaN(Number(alphaComponent))) { if (Number.isNaN(Number(alphaComponent))) {
if ((syntaxFlags instanceof Set) && syntaxFlags.has(NONE_KEY)) { if (syntaxFlags instanceof Set && syntaxFlags.has(KEY_NONE)) {
alpha = NONE; alpha = NONE;
} else { } else {
alpha = 0; alpha = 0;
} }
} else { } else {
alpha = roundToPrecision(alphaComponent as number, OCT); alpha = roundToPrecision(Number(alphaComponent), OCT);
} }
let v1: number | string; let v1: number | string;
let v2: number | string; let v2: number | string;
@ -488,7 +485,7 @@ export function resolveRelativeColor(
[v1, v2, v3] = channelsComponent; [v1, v2, v3] = channelsComponent;
let resolvedValue; let resolvedValue;
if (REG_CS_CIE.test(colorNotation)) { if (REG_CS_CIE.test(colorNotation)) {
const hasNone = (syntaxFlags instanceof Set) && syntaxFlags.has(NONE_KEY); const hasNone = syntaxFlags instanceof Set && syntaxFlags.has(KEY_NONE);
if (Number.isNaN(v1)) { if (Number.isNaN(v1)) {
if (hasNone) { if (hasNone) {
v1 = NONE; v1 = NONE;
@ -531,9 +528,9 @@ export function resolveRelativeColor(
if (Number.isNaN(v3)) { if (Number.isNaN(v3)) {
v3 = 0; v3 = 0;
} }
let [r, g, b] = colorToRgb( let [r, g, b] = convertColorToRgb(
`${colorNotation}(${v1} ${v2} ${v3} / ${alpha})` `${colorNotation}(${v1} ${v2} ${v3} / ${alpha})`
) as [number, number, number]; ) as ColorChannels;
r = roundToPrecision(r / MAX_RGB, DEC); r = roundToPrecision(r / MAX_RGB, DEC);
g = roundToPrecision(g / MAX_RGB, DEC); g = roundToPrecision(g / MAX_RGB, DEC);
b = roundToPrecision(b / MAX_RGB, DEC); b = roundToPrecision(b / MAX_RGB, DEC);
@ -544,7 +541,7 @@ export function resolveRelativeColor(
} }
} else { } else {
const cs = colorNotation === 'rgb' ? 'srgb' : colorNotation; const cs = colorNotation === 'rgb' ? 'srgb' : colorNotation;
const hasNone = (syntaxFlags instanceof Set) && syntaxFlags.has(NONE_KEY); const hasNone = syntaxFlags instanceof Set && syntaxFlags.has(KEY_NONE);
if (Number.isNaN(v1)) { if (Number.isNaN(v1)) {
if (hasNone) { if (hasNone) {
v1 = NONE; v1 = NONE;
@ -578,8 +575,6 @@ export function resolveRelativeColor(
resolvedValue = `color(${cs} ${v1} ${v2} ${v3} / ${alpha})`; resolvedValue = `color(${cs} ${v1} ${v2} ${v3} / ${alpha})`;
} }
} }
if (cacheKey) { setCache(cacheKey, resolvedValue);
cachedResults.set(cacheKey, resolvedValue);
}
return resolvedValue; return resolvedValue;
} }

View File

@ -1,8 +1,14 @@
/** /**
* resolve.js * resolve
*/ */
import { LRUCache } from 'lru-cache'; import {
CacheItem,
NullObject,
createCacheKey,
getCache,
setCache
} from './cache';
import { import {
convertRgbToHex, convertRgbToHex,
resolveColorFunc, resolveColorFunc,
@ -11,66 +17,349 @@ import {
} from './color'; } from './color';
import { isString } from './common'; import { isString } from './common';
import { cssCalc } from './css-calc'; import { cssCalc } from './css-calc';
import { cssVar } from './css-var'; import { resolveVar } from './css-var';
import { resolveRelativeColor } from './relative-color'; import { resolveRelativeColor } from './relative-color';
import { valueToJsonString } from './util'; import {
ComputedColorChannels,
Options,
SpecifiedColorChannels
} from './typedef';
/* constants */ /* constants */
import { import {
FN_COLOR, FN_COLOR,
FN_MIX, FN_MIX,
SYN_FN_MATH_CALC, SYN_FN_CALC,
SYN_FN_REL, SYN_FN_REL,
SYN_FN_VAR, SYN_FN_VAR,
VAL_COMP, VAL_COMP,
VAL_SPEC VAL_SPEC
} from './constant.js'; } from './constant';
const NAMESPACE = 'resolve';
const RGB_TRANSPARENT = 'rgba(0, 0, 0, 0)'; const RGB_TRANSPARENT = 'rgba(0, 0, 0, 0)';
/* regexp */ /* regexp */
const REG_FN_MATH_CALC = new RegExp(SYN_FN_MATH_CALC); const REG_FN_CALC = new RegExp(SYN_FN_CALC);
const REG_FN_REL = new RegExp(SYN_FN_REL); const REG_FN_REL = new RegExp(SYN_FN_REL);
const REG_FN_VAR = new RegExp(SYN_FN_VAR); const REG_FN_VAR = new RegExp(SYN_FN_VAR);
/* cached results */ /**
export const cachedResults = new LRUCache({ * resolve color
max: 4096 * @param value - CSS color value
}); * @param [opt] - options
* @returns resolved color
*/
export const resolveColor = (
value: string,
opt: Options = {}
): string | NullObject => {
if (isString(value)) {
value = value.trim();
} else {
throw new TypeError(`${value} is not a string.`);
}
const { currentColor = '', format = VAL_COMP, nullable = false } = opt;
const cacheKey: string = createCacheKey(
{
namespace: NAMESPACE,
name: 'resolve',
value
},
opt
);
const cachedResult = getCache(cacheKey);
if (cachedResult instanceof CacheItem) {
if (cachedResult.isNull) {
return cachedResult as NullObject;
}
return cachedResult.item as string;
}
if (REG_FN_VAR.test(value)) {
if (format === VAL_SPEC) {
setCache(cacheKey, value);
return value;
}
const resolvedValue = resolveVar(value, opt);
if (resolvedValue instanceof NullObject) {
switch (format) {
case 'hex':
case 'hexAlpha': {
setCache(cacheKey, resolvedValue);
return resolvedValue;
}
default: {
if (nullable) {
setCache(cacheKey, resolvedValue);
return resolvedValue;
}
const res = RGB_TRANSPARENT;
setCache(cacheKey, res);
return res;
}
}
} else {
value = resolvedValue;
}
}
if (opt.format !== format) {
opt.format = format;
}
value = value.toLowerCase();
if (REG_FN_REL.test(value)) {
const resolvedValue = resolveRelativeColor(value, opt);
if (format === VAL_COMP) {
let res;
if (resolvedValue instanceof NullObject) {
if (nullable) {
res = resolvedValue;
} else {
res = RGB_TRANSPARENT;
}
} else {
res = resolvedValue;
}
setCache(cacheKey, res);
return res;
}
if (format === VAL_SPEC) {
let res = '';
if (resolvedValue instanceof NullObject) {
res = '';
} else {
res = resolvedValue;
}
setCache(cacheKey, res);
return res;
}
if (resolvedValue instanceof NullObject) {
value = '';
} else {
value = resolvedValue;
}
}
if (REG_FN_CALC.test(value)) {
value = cssCalc(value, opt);
}
let cs = '';
let r = NaN;
let g = NaN;
let b = NaN;
let alpha = NaN;
if (value === 'transparent') {
switch (format) {
case VAL_SPEC: {
setCache(cacheKey, value);
return value;
}
case 'hex': {
setCache(cacheKey, null);
return new NullObject();
}
case 'hexAlpha': {
const res = '#00000000';
setCache(cacheKey, res);
return res;
}
case VAL_COMP:
default: {
const res = RGB_TRANSPARENT;
setCache(cacheKey, res);
return res;
}
}
} else if (value === 'currentcolor') {
if (format === VAL_SPEC) {
setCache(cacheKey, value);
return value;
}
if (currentColor) {
let resolvedValue;
if (currentColor.startsWith(FN_MIX)) {
resolvedValue = resolveColorMix(currentColor, opt);
} else if (currentColor.startsWith(FN_COLOR)) {
resolvedValue = resolveColorFunc(currentColor, opt);
} else {
resolvedValue = resolveColorValue(currentColor, opt);
}
if (resolvedValue instanceof NullObject) {
setCache(cacheKey, resolvedValue);
return resolvedValue;
}
[cs, r, g, b, alpha] = resolvedValue as ComputedColorChannels;
} else if (format === VAL_COMP) {
const res = RGB_TRANSPARENT;
setCache(cacheKey, res);
return res;
}
} else if (format === VAL_SPEC) {
if (value.startsWith(FN_MIX)) {
const res = resolveColorMix(value, opt) as string;
setCache(cacheKey, res);
return res;
} else if (value.startsWith(FN_COLOR)) {
const [scs, rr, gg, bb, aa] = resolveColorFunc(
value,
opt
) as SpecifiedColorChannels;
let res = '';
if (aa === 1) {
res = `color(${scs} ${rr} ${gg} ${bb})`;
} else {
res = `color(${scs} ${rr} ${gg} ${bb} / ${aa})`;
}
setCache(cacheKey, res);
return res;
} else {
const rgb = resolveColorValue(value, opt);
if (isString(rgb)) {
setCache(cacheKey, rgb);
return rgb;
}
const [scs, rr, gg, bb, aa] = rgb as SpecifiedColorChannels;
let res = '';
if (scs === 'rgb') {
if (aa === 1) {
res = `${scs}(${rr}, ${gg}, ${bb})`;
} else {
res = `${scs}a(${rr}, ${gg}, ${bb}, ${aa})`;
}
} else if (aa === 1) {
res = `${scs}(${rr} ${gg} ${bb})`;
} else {
res = `${scs}(${rr} ${gg} ${bb} / ${aa})`;
}
setCache(cacheKey, res);
return res;
}
} else if (value.startsWith(FN_MIX)) {
if (/currentcolor/.test(value)) {
if (currentColor) {
value = value.replace(/currentcolor/g, currentColor);
}
}
if (/transparent/.test(value)) {
value = value.replace(/transparent/g, RGB_TRANSPARENT);
}
const resolvedValue = resolveColorMix(value, opt);
if (resolvedValue instanceof NullObject) {
setCache(cacheKey, resolvedValue);
return resolvedValue;
}
[cs, r, g, b, alpha] = resolvedValue as ComputedColorChannels;
} else if (value.startsWith(FN_COLOR)) {
const resolvedValue = resolveColorFunc(value, opt);
if (resolvedValue instanceof NullObject) {
setCache(cacheKey, resolvedValue);
return resolvedValue;
}
[cs, r, g, b, alpha] = resolvedValue as ComputedColorChannels;
} else if (value) {
const resolvedValue = resolveColorValue(value, opt);
if (resolvedValue instanceof NullObject) {
setCache(cacheKey, resolvedValue);
return resolvedValue;
}
[cs, r, g, b, alpha] = resolvedValue as ComputedColorChannels;
}
let res = '';
switch (format) {
case 'hex': {
if (
Number.isNaN(r) ||
Number.isNaN(g) ||
Number.isNaN(b) ||
Number.isNaN(alpha) ||
alpha === 0
) {
setCache(cacheKey, null);
return new NullObject();
}
res = convertRgbToHex([r, g, b, 1]);
break;
}
case 'hexAlpha': {
if (
Number.isNaN(r) ||
Number.isNaN(g) ||
Number.isNaN(b) ||
Number.isNaN(alpha)
) {
setCache(cacheKey, null);
return new NullObject();
}
res = convertRgbToHex([r, g, b, alpha]);
break;
}
case VAL_COMP:
default: {
switch (cs) {
case 'rgb': {
if (alpha === 1) {
res = `${cs}(${r}, ${g}, ${b})`;
} else {
res = `${cs}a(${r}, ${g}, ${b}, ${alpha})`;
}
break;
}
case 'lab':
case 'lch':
case 'oklab':
case 'oklch': {
if (alpha === 1) {
res = `${cs}(${r} ${g} ${b})`;
} else {
res = `${cs}(${r} ${g} ${b} / ${alpha})`;
}
break;
}
// color()
default: {
if (alpha === 1) {
res = `color(${cs} ${r} ${g} ${b})`;
} else {
res = `color(${cs} ${r} ${g} ${b} / ${alpha})`;
}
}
}
}
}
setCache(cacheKey, res);
return res;
};
/** /**
* resolve CSS color * resolve CSS color
* @param {string} color - color value * @param value
* - CSS color value
* - system colors are not supported * - system colors are not supported
* @param {object} [opt] - options * @param [opt] - options
* @param {string} [opt.currentColor] * @param [opt.currentColor]
* - color to use for `currentcolor` keyword * - color to use for `currentcolor` keyword
* - if omitted, it will be treated as a missing color * - if omitted, it will be treated as a missing color
* i.e. `rgb(none none none / none)` * i.e. `rgb(none none none / none)`
* @param {object} [opt.customProperty] * @param [opt.customProperty]
* - custom properties * - custom properties
* - pair of `--` prefixed property name and value, * - pair of `--` prefixed property name and value,
* e.g. `customProperty: { '--some-color': '#0000ff' }` * e.g. `customProperty: { '--some-color': '#0000ff' }`
* - and/or `callback` function to get the value of the custom property, * - and/or `callback` function to get the value of the custom property,
* e.g. `customProperty: { callback: someDeclaration.getPropertyValue }` * e.g. `customProperty: { callback: someDeclaration.getPropertyValue }`
* @param {object} [opt.dimension] * @param [opt.dimension]
* - dimension, convert relative length to pixels * - dimension, convert relative length to pixels
* - pair of unit and it's value as a number in pixels, * - pair of unit and it's value as a number in pixels,
* e.g. `dimension: { em: 12, rem: 16, vw: 10.26 }` * e.g. `dimension: { em: 12, rem: 16, vw: 10.26 }`
* - and/or `callback` function to get the value as a number in pixels, * - and/or `callback` function to get the value as a number in pixels,
* e.g. `dimension: { callback: convertUnitToPixel }` * e.g. `dimension: { callback: convertUnitToPixel }`
* @param {string} [opt.format] * @param [opt.format]
* - output format, one of below * - output format, one of below
* - `computedValue` (default), [computed value][139] of the color * - `computedValue` (default), [computed value][139] of the color
* - `specifiedValue`, [specified value][140] of the color * - `specifiedValue`, [specified value][140] of the color
* - `hex`, hex color notation, i.e. `rrggbb` * - `hex`, hex color notation, i.e. `rrggbb`
* - `hexAlpha`, hex color notation with alpha channel, i.e. `#rrggbbaa` * - `hexAlpha`, hex color notation with alpha channel, i.e. `#rrggbbaa`
* @param {*} [opt.key] - key e.g. CSS property `background-color` * @returns
* @returns {?string|Array}
* - one of rgba?(), #rrggbb(aa)?, color-name, '(empty-string)', * - one of rgba?(), #rrggbb(aa)?, color-name, '(empty-string)',
* color(color-space r g b / alpha), color(color-space x y z / alpha), * color(color-space r g b / alpha), color(color-space x y z / alpha),
* lab(l a b / alpha), lch(l c h / alpha), oklab(l a b / alpha), * lab(l a b / alpha), lch(l c h / alpha), oklab(l a b / alpha),
* oklch(l c h / alpha), null or [key, rgba?()] etc. if `key` is specified * oklch(l c h / alpha), null
* - in `computedValue`, values are numbers, however `rgb()` values are * - in `computedValue`, values are numbers, however `rgb()` values are
* integers * integers
* - in `specifiedValue`, returns `empty string` for unknown and/or invalid * - in `specifiedValue`, returns `empty string` for unknown and/or invalid
@ -80,369 +369,11 @@ export const cachedResults = new LRUCache({
* - in `hexAlpha`, returns `#00000000` for `transparent`, * - in `hexAlpha`, returns `#00000000` for `transparent`,
* however returns `null` if any of `r`, `g`, `b`, `alpha` is not a number * however returns `null` if any of `r`, `g`, `b`, `alpha` is not a number
*/ */
export const resolve = ( export const resolve = (value: string, opt: Options = {}): string | null => {
color: string, opt.nullable = false;
opt: { const resolvedValue = resolveColor(value, opt);
currentColor?: string; if (resolvedValue instanceof NullObject) {
customProperty?: object; return null;
dimension?: object;
format?: string;
key?: any;
} = {}
): (string | Array<any>) | null => {
if (isString(color)) {
color = color.trim();
} else {
throw new TypeError(`${color} is not a string.`);
} }
const { currentColor, customProperty = {}, format = VAL_COMP, key } = opt; return resolvedValue as string;
let cacheKey;
if (
!REG_FN_VAR.test(color) ||
typeof (
customProperty as { callback?: (value: string) => string }
).callback === 'function'
) {
cacheKey = `{resolve:${color},opt:${valueToJsonString(opt)}}`;
if (cachedResults.has(cacheKey)) {
return cachedResults.get(cacheKey) as string | Array<any>;
}
}
let res, cs, r, g, b, alpha;
if (REG_FN_VAR.test(color)) {
if (format === VAL_SPEC) {
if (cacheKey) {
cachedResults.set(cacheKey, color);
}
return color;
}
const resolvedColor = cssVar(color, opt);
if (resolvedColor) {
color = resolvedColor;
} else {
switch (format) {
case 'hex':
case 'hexAlpha': {
if (cacheKey) {
cachedResults.set(cacheKey, null!);
}
return null;
}
default: {
res = RGB_TRANSPARENT;
if (cacheKey) {
cachedResults.set(cacheKey, res);
}
return res;
}
}
}
}
if (opt.format !== format) {
opt.format = format;
}
color = color.toLowerCase();
if (REG_FN_REL.test(color)) {
const resolvedColor = resolveRelativeColor(color, opt) as string | null;
if (format === VAL_COMP) {
if (resolvedColor) {
res = resolvedColor;
} else {
res = RGB_TRANSPARENT;
}
if (cacheKey) {
cachedResults.set(cacheKey, res);
}
return res;
}
if (format === VAL_SPEC) {
if (resolvedColor) {
res = resolvedColor;
} else {
res = '';
}
if (cacheKey) {
cachedResults.set(cacheKey, res);
}
return res;
}
if (resolvedColor) {
color = resolvedColor;
} else {
color = '';
}
}
if (REG_FN_MATH_CALC.test(color)) {
const resolvedColor = cssCalc(color, opt) as string | null;
if (resolvedColor) {
color = resolvedColor;
} else {
color = '';
}
}
if (color === 'transparent') {
switch (format) {
case VAL_SPEC: {
if (cacheKey) {
cachedResults.set(cacheKey, color);
}
return color;
}
case 'hex': {
if (cacheKey) {
cachedResults.set(cacheKey, null!);
}
return null;
}
case 'hexAlpha': {
res = '#00000000';
if (cacheKey) {
cachedResults.set(cacheKey, res);
}
return res;
}
case VAL_COMP:
default: {
res = RGB_TRANSPARENT;
if (cacheKey) {
cachedResults.set(cacheKey, res);
}
return res;
}
}
} else if (color === 'currentcolor') {
if (format === VAL_SPEC) {
if (cacheKey) {
cachedResults.set(cacheKey, color);
}
return color;
}
if (currentColor) {
if (currentColor.startsWith(FN_MIX)) {
[cs, r, g, b, alpha] = resolveColorMix(currentColor, opt) as [
string,
number,
number,
number,
number
];
} else if (currentColor.startsWith(FN_COLOR)) {
[cs, r, g, b, alpha] = resolveColorFunc(currentColor, opt) as [
string,
number,
number,
number,
number
];
} else {
[cs, r, g, b, alpha] = resolveColorValue(currentColor, opt) as [
string,
number,
number,
number,
number
];
}
} else if (format === VAL_COMP) {
res = RGB_TRANSPARENT;
if (cacheKey) {
cachedResults.set(cacheKey, res);
}
return res;
}
} else if (format === VAL_SPEC) {
if (color.startsWith(FN_MIX)) {
res = resolveColorMix(color, opt);
if (cacheKey) {
cachedResults.set(cacheKey, res!);
}
return res;
} else if (color.startsWith(FN_COLOR)) {
[cs, r, g, b, alpha] = resolveColorFunc(color, opt) as [
string,
number | string,
number | string,
number | string,
number | string
];
if (alpha === 1) {
res = `color(${cs} ${r} ${g} ${b})`;
} else {
res = `color(${cs} ${r} ${g} ${b} / ${alpha})`;
}
if (cacheKey) {
cachedResults.set(cacheKey, res);
}
return res;
} else {
const rgb = resolveColorValue(color, opt);
if (!rgb) {
res = '';
if (cacheKey) {
cachedResults.set(cacheKey, res);
}
return res;
}
[cs, r, g, b, alpha] = rgb;
if (cs === 'rgb') {
if (alpha === 1) {
res = `${cs}(${r}, ${g}, ${b})`;
} else {
res = `${cs}a(${r}, ${g}, ${b}, ${alpha})`;
}
if (cacheKey) {
cachedResults.set(cacheKey, res);
}
return res;
}
if (alpha === 1) {
res = `${cs}(${r} ${g} ${b})`;
} else {
res = `${cs}(${r} ${g} ${b} / ${alpha})`;
}
if (cacheKey) {
cachedResults.set(cacheKey, res);
}
return res;
}
} else if (/currentcolor/.test(color)) {
if (currentColor) {
color = color.replace(/currentcolor/g, currentColor);
}
if (/transparent/.test(color)) {
color = color.replace(/transparent/g, RGB_TRANSPARENT);
}
if (color.startsWith(FN_MIX)) {
[cs, r, g, b, alpha] = resolveColorMix(color, opt) as [
string,
number,
number,
number,
number
];
}
} else if (/transparent/.test(color)) {
color = color.replace(/transparent/g, RGB_TRANSPARENT);
if (color.startsWith(FN_MIX)) {
[cs, r, g, b, alpha] = resolveColorMix(color, opt) as [
string,
number,
number,
number,
number
];
}
} else if (color.startsWith(FN_MIX)) {
[cs, r, g, b, alpha] = resolveColorMix(color, opt) as [
string,
number,
number,
number,
number
];
} else if (color.startsWith(FN_COLOR)) {
[cs, r, g, b, alpha] = resolveColorFunc(color, opt) as [
string,
number,
number,
number,
number
];
} else if (color) {
[cs, r, g, b, alpha] = resolveColorValue(color, opt) as [
string,
number,
number,
number,
number
];
}
switch (format) {
case 'hex': {
let hex;
if (
isNaN(r as number) ||
isNaN(g as number) ||
isNaN(b as number) ||
isNaN(alpha as number) ||
alpha === 0
) {
hex = null;
} else {
hex = convertRgbToHex([r as number, g as number, b as number]);
}
if (key) {
res = [key, hex];
} else {
res = hex;
}
break;
}
case 'hexAlpha': {
let hex;
if (
isNaN(r as number) ||
isNaN(g as number) ||
isNaN(b as number) ||
isNaN(alpha as number)
) {
hex = null;
} else {
hex = convertRgbToHex([
r as number,
g as number,
b as number,
alpha as number
]);
}
if (key) {
res = [key, hex];
} else {
res = hex;
}
break;
}
case VAL_COMP:
default: {
let value;
switch (cs) {
case 'rgb': {
if (alpha === 1) {
value = `${cs}(${r}, ${g}, ${b})`;
} else {
value = `${cs}a(${r}, ${g}, ${b}, ${alpha})`;
}
break;
}
case 'lab':
case 'lch':
case 'oklab':
case 'oklch': {
if (alpha === 1) {
value = `${cs}(${r} ${g} ${b})`;
} else {
value = `${cs}(${r} ${g} ${b} / ${alpha})`;
}
break;
}
// color()
default: {
if (alpha === 1) {
value = `color(${cs} ${r} ${g} ${b})`;
} else {
value = `color(${cs} ${r} ${g} ${b} / ${alpha})`;
}
}
}
if (key) {
res = [key, value];
} else {
res = value;
}
}
}
if (cacheKey) {
cachedResults.set(cacheKey, res!);
}
return res;
}; };

86
node_modules/@asamuzakjp/css-color/src/js/typedef.ts generated vendored Normal file
View File

@ -0,0 +1,86 @@
/**
* typedef
*/
/* type definitions */
/**
* @typedef Options - options
* @property [alpha] - enable alpha
* @property [colorSpace] - color space
* @property [currentColor] - color for currentcolor
* @property [customPropeerty] - custom properties
* @property [d50] - white point in d50
* @property [dimension] - dimension
* @property [format] - output format
* @property [key] - key
*/
export interface Options {
alpha?: boolean;
colorSpace?: string;
currentColor?: string;
customProperty?: Record<string, string | ((K: string) => string)>;
d50?: boolean;
delimiter?: string | string[];
dimension?: Record<string, number | ((K: string) => number)>;
format?: string;
nullable?: boolean;
}
/**
* @type ColorChannels - color channels
*/
export type ColorChannels = [x: number, y: number, z: number, alpha: number];
/**
* @type StringColorChannels - color channels
*/
export type StringColorChannels = [
x: string,
y: string,
z: string,
alpha: string | undefined
];
/**
* @type StringColorSpacedChannels - specified value
*/
export type StringColorSpacedChannels = [
cs: string,
x: string,
y: string,
z: string,
alpha: string | undefined
];
/**
* @type ComputedColorChannels - computed value
*/
export type ComputedColorChannels = [
cs: string,
x: number,
y: number,
z: number,
alpha: number
];
/**
* @type SpecifiedColorChannels - specified value
*/
export type SpecifiedColorChannels = [
cs: string,
x: number | string,
y: number | string,
z: number | string,
alpha: number | string
];
/**
* @type MatchedRegExp - matched regexp array
*/
export type MatchedRegExp = [
match: string,
gr1: string,
gr2: string,
gr3: string,
gr4: string
];

View File

@ -1,13 +1,29 @@
/** /**
* util.js * util
*/ */
import { TokenType, tokenize } from '@csstools/css-tokenizer';
import { CacheItem, createCacheKey, getCache, setCache } from './cache';
import { isString } from './common'; import { isString } from './common';
import { resolve } from './resolve'; import { resolveColor } from './resolve';
import { Options } from './typedef';
/* constants */ /* constants */
import { NAMED_COLORS } from './color'; import { NAMED_COLORS } from './color';
import { SYN_COLOR_TYPE, SYN_MIX, VAL_SPEC } from './constant'; import { SYN_COLOR_TYPE, SYN_MIX, VAL_SPEC } from './constant';
const {
CloseParen: PAREN_CLOSE,
Comma: COMMA,
Comment: COMMENT,
EOF,
Function: FUNC,
Ident: IDENT,
OpenParen: PAREN_OPEN,
Whitespace: W_SPACE
} = TokenType;
const NAMESPACE = 'util';
/* numeric constants */
const DEC = 10; const DEC = 10;
const HEX = 16; const HEX = 16;
const DEG = 360; const DEG = 360;
@ -15,17 +31,141 @@ const DEG_HALF = 180;
/* regexp */ /* regexp */
const REG_COLOR = new RegExp(`^(?:${SYN_COLOR_TYPE})$`); const REG_COLOR = new RegExp(`^(?:${SYN_COLOR_TYPE})$`);
const REG_MIX = new RegExp(`${SYN_MIX}`); const REG_MIX = new RegExp(SYN_MIX);
/**
* split value
* @param value - CSS value
* @param [delimiter] - comma or space
* @returns array of values, NOTE: comments are stripped
*/
export const splitValue = (value: string, delimiter: string = ''): string[] => {
if (isString(value)) {
value = value.trim();
} else {
throw new TypeError(`${value} is not a string.`);
}
const cacheKey: string = createCacheKey(
{
namespace: NAMESPACE,
name: 'splitValue',
value
},
{
delimiter
}
);
const cachedResult = getCache(cacheKey);
if (cachedResult instanceof CacheItem) {
return cachedResult.item as string[];
}
const regDelimiter = delimiter === ',' ? /^,$/ : /^\s+$/;
const tokens = tokenize({ css: value });
let nest = 0;
let str = '';
const res: string[] = [];
while (tokens.length) {
const [type, value] = tokens.shift() as [TokenType, string];
switch (type) {
case COMMA: {
if (regDelimiter.test(value)) {
if (nest === 0) {
res.push(str.trim());
str = '';
} else {
str += value;
}
} else {
str += value;
}
break;
}
case COMMENT: {
break;
}
case FUNC:
case PAREN_OPEN: {
str += value;
nest++;
break;
}
case PAREN_CLOSE: {
str += value;
nest--;
break;
}
case W_SPACE: {
if (regDelimiter.test(value)) {
if (nest === 0) {
if (str) {
res.push(str.trim());
str = '';
}
} else {
str += ' ';
}
} else if (!str.endsWith(' ')) {
str += ' ';
}
break;
}
default: {
if (type === EOF) {
res.push(str.trim());
str = '';
} else {
str += value;
}
}
}
}
setCache(cacheKey, res);
return res;
};
/**
* extract dashed-ident tokens
* @param value - CSS value
* @returns array of dashed-ident tokens
*/
export const extractDashedIdent = (value: string): string[] => {
if (isString(value)) {
value = value.trim();
} else {
throw new TypeError(`${value} is not a string.`);
}
const cacheKey: string = createCacheKey({
namespace: NAMESPACE,
name: 'extractDashedIdent',
value
});
const cachedResult = getCache(cacheKey);
if (cachedResult instanceof CacheItem) {
return cachedResult.item as string[];
}
const tokens = tokenize({ css: value });
const items = new Set();
while (tokens.length) {
const [type, value] = tokens.shift() as [TokenType, string];
if (type === IDENT && value.startsWith('--')) {
items.add(value);
}
}
const res = [...items] as string[];
setCache(cacheKey, res);
return res;
};
/** /**
* is color * is color
* @param {string} value - value * @param value - CSS value
* @returns {boolean} - result * @param [opt] - options
* @returns result
*/ */
export const isColor = (value: string): boolean => { export const isColor = (value: unknown, opt: Options = {}): boolean => {
if (isString(value)) { if (isString(value)) {
value = value.toLowerCase().trim(); value = value.toLowerCase().trim();
if (value) { if (value && isString(value)) {
if (/^[a-z]+$/.test(value)) { if (/^[a-z]+$/.test(value)) {
if ( if (
/^(?:currentcolor|transparent)$/.test(value) || /^(?:currentcolor|transparent)$/.test(value) ||
@ -36,13 +176,14 @@ export const isColor = (value: string): boolean => {
} else if (REG_COLOR.test(value) || REG_MIX.test(value)) { } else if (REG_COLOR.test(value) || REG_MIX.test(value)) {
return true; return true;
} else { } else {
const resolvedValue = resolve(value, { opt.nullable = true;
format: VAL_SPEC if (!opt.format) {
}); opt.format = VAL_SPEC;
}
const resolvedValue = resolveColor(value, opt);
if (resolvedValue) { if (resolvedValue) {
return true; return true;
} }
return false;
} }
} }
} }
@ -51,12 +192,12 @@ export const isColor = (value: string): boolean => {
/** /**
* value to JSON string * value to JSON string
* @param {*} value - value * @param value - CSS value
* @param {boolean} func - stringify function * @param [func] - stringify function
* @returns {string} - stringified value in JSON notation * @returns stringified value in JSON notation
*/ */
export const valueToJsonString = ( export const valueToJsonString = (
value: any, value: unknown,
func: boolean = false func: boolean = false
): string => { ): string => {
if (typeof value === 'undefined') { if (typeof value === 'undefined') {
@ -68,7 +209,7 @@ export const valueToJsonString = (
replacedValue = null; replacedValue = null;
} else if (typeof val === 'function') { } else if (typeof val === 'function') {
if (func) { if (func) {
replacedValue = val.toString(); replacedValue = val.toString().replace(/\s/g, '').substring(0, HEX);
} else { } else {
replacedValue = val.name; replacedValue = val.name;
} }
@ -86,16 +227,16 @@ export const valueToJsonString = (
/** /**
* round to specified precision * round to specified precision
* @param {number} value - value * @param value - numeric value
* @param {number} bit - minimum bits * @param bit - minimum bits
* @returns {number} - rounded value * @returns rounded value
*/ */
export const roundToPrecision = (value: number, bit: number = 0): number => { export const roundToPrecision = (value: number, bit: number = 0): number => {
if (!Number.isFinite(value)) { if (!Number.isFinite(value)) {
throw new TypeError(`${value} is not a number.`); throw new TypeError(`${value} is not a finite number.`);
} }
if (!Number.isFinite(bit)) { if (!Number.isFinite(bit)) {
throw new TypeError(`${bit} is not a number.`); throw new TypeError(`${bit} is not a finite number.`);
} else if (bit < 0 || bit > HEX) { } else if (bit < 0 || bit > HEX) {
throw new RangeError(`${bit} is not between 0 and ${HEX}.`); throw new RangeError(`${bit} is not between 0 and ${HEX}.`);
} }
@ -115,21 +256,21 @@ export const roundToPrecision = (value: number, bit: number = 0): number => {
/** /**
* interpolate hue * interpolate hue
* @param {number} hueA - hue * @param hueA - hue value
* @param {number} hueB - hue * @param hueB - hue value
* @param {string} arc - arc * @param arc - shorter | longer | increasing | decreasing
* @returns {Array} - [hueA, hueB] * @returns result - [hueA, hueB]
*/ */
export const interpolateHue = ( export const interpolateHue = (
hueA: number, hueA: number,
hueB: number, hueB: number,
arc: string = 'shorter' arc: string = 'shorter'
): Array<number> => { ): [number, number] => {
if (!Number.isFinite(hueA)) { if (!Number.isFinite(hueA)) {
throw new TypeError(`${hueA} is not a number.`); throw new TypeError(`${hueA} is not a finite number.`);
} }
if (!Number.isFinite(hueB)) { if (!Number.isFinite(hueB)) {
throw new TypeError(`${hueB} is not a number.`); throw new TypeError(`${hueB} is not a finite number.`);
} }
switch (arc) { switch (arc) {
case 'decreasing': { case 'decreasing': {

View File

@ -5,7 +5,7 @@ Object.defineProperty(exports, "__esModule", {
}); });
exports.default = loadCodeDefault; exports.default = loadCodeDefault;
exports.supportsESM = void 0; exports.supportsESM = void 0;
var _async3 = require("../../gensync-utils/async.js"); var _async = require("../../gensync-utils/async.js");
function _path() { function _path() {
const data = require("path"); const data = require("path");
_path = function () { _path = function () {
@ -89,7 +89,6 @@ const SUPPORTED_EXTENSIONS = {
}; };
const asyncModules = new Set(); const asyncModules = new Set();
function* loadCodeDefault(filepath, loader, esmError, tlaError) { function* loadCodeDefault(filepath, loader, esmError, tlaError) {
var _async2;
let async; let async;
const ext = _path().extname(filepath); const ext = _path().extname(filepath);
const isTS = ext === ".ts" || ext === ".cts" || ext === ".mts"; const isTS = ext === ".ts" || ext === ".cts" || ext === ".mts";
@ -114,9 +113,8 @@ function* loadCodeDefault(filepath, loader, esmError, tlaError) {
} }
} catch (e) { } catch (e) {
if (e.code === "ERR_REQUIRE_ASYNC_MODULE" || e.code === "ERR_REQUIRE_CYCLE_MODULE" && asyncModules.has(filepath)) { if (e.code === "ERR_REQUIRE_ASYNC_MODULE" || e.code === "ERR_REQUIRE_CYCLE_MODULE" && asyncModules.has(filepath)) {
var _async;
asyncModules.add(filepath); asyncModules.add(filepath);
if (!((_async = async) != null ? _async : async = yield* (0, _async3.isAsync)())) { if (!(async != null ? async : async = yield* (0, _async.isAsync)())) {
throw new _configError.default(tlaError, filepath); throw new _configError.default(tlaError, filepath);
} }
} else if (e.code === "ERR_REQUIRE_ESM" || type === "esm") {} else { } else if (e.code === "ERR_REQUIRE_ESM" || type === "esm") {} else {
@ -124,9 +122,9 @@ function* loadCodeDefault(filepath, loader, esmError, tlaError) {
} }
} }
case "auto esm": case "auto esm":
if ((_async2 = async) != null ? _async2 : async = yield* (0, _async3.isAsync)()) { if (async != null ? async : async = yield* (0, _async.isAsync)()) {
const promise = isTS ? ensureTsSupport(filepath, ext, () => loadMjsFromPath(filepath)) : loadMjsFromPath(filepath); const promise = isTS ? ensureTsSupport(filepath, ext, () => loadMjsFromPath(filepath)) : loadMjsFromPath(filepath);
return (yield* (0, _async3.waitFor)(promise)).default; return (yield* (0, _async.waitFor)(promise)).default;
} }
throw new _configError.default(esmError, filepath); throw new _configError.default(esmError, filepath);
default: default:

File diff suppressed because one or more lines are too long

View File

@ -21,7 +21,7 @@ var _options = require("./validation/options.js");
var _index = require("./files/index.js"); var _index = require("./files/index.js");
var _resolveTargets = require("./resolve-targets.js"); var _resolveTargets = require("./resolve-targets.js");
const _excluded = ["showIgnoredFiles"]; const _excluded = ["showIgnoredFiles"];
function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (e.includes(n)) continue; t[n] = r[n]; } return t; } function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
function resolveRootMode(rootDir, rootMode) { function resolveRootMode(rootDir, rootMode) {
switch (rootMode) { switch (rootMode) {
case "root": case "root":

File diff suppressed because one or more lines are too long

View File

@ -212,7 +212,7 @@ var _transformFile = require("./transform-file.js");
var _transformAst = require("./transform-ast.js"); var _transformAst = require("./transform-ast.js");
var _parse = require("./parse.js"); var _parse = require("./parse.js");
; ;
const version = exports.version = "7.26.9"; const version = exports.version = "7.26.10";
const resolvePlugin = (name, dirname) => resolvers.resolvePlugin(name, dirname, false).filepath; const resolvePlugin = (name, dirname) => resolvers.resolvePlugin(name, dirname, false).filepath;
exports.resolvePlugin = resolvePlugin; exports.resolvePlugin = resolvePlugin;
const resolvePreset = (name, dirname) => resolvers.resolvePreset(name, dirname, false).filepath; const resolvePreset = (name, dirname) => resolvers.resolvePreset(name, dirname, false).filepath;

File diff suppressed because one or more lines are too long

View File

@ -4,32 +4,52 @@ Object.defineProperty(exports, "__esModule", {
value: true value: true
}); });
exports.default = _default; exports.default = _default;
function deepClone(value, cache) { const circleSet = new Set();
let depth = 0;
function deepClone(value, cache, allowCircle) {
if (value !== null) { if (value !== null) {
if (cache.has(value)) return cache.get(value); if (allowCircle) {
if (cache.has(value)) return cache.get(value);
} else if (++depth > 250) {
if (circleSet.has(value)) {
depth = 0;
circleSet.clear();
throw new Error("Babel-deepClone: Cycles are not allowed in AST");
}
circleSet.add(value);
}
let cloned; let cloned;
if (Array.isArray(value)) { if (Array.isArray(value)) {
cloned = new Array(value.length); cloned = new Array(value.length);
cache.set(value, cloned); if (allowCircle) cache.set(value, cloned);
for (let i = 0; i < value.length; i++) { for (let i = 0; i < value.length; i++) {
cloned[i] = typeof value[i] !== "object" ? value[i] : deepClone(value[i], cache); cloned[i] = typeof value[i] !== "object" ? value[i] : deepClone(value[i], cache, allowCircle);
} }
} else { } else {
cloned = {}; cloned = {};
cache.set(value, cloned); if (allowCircle) cache.set(value, cloned);
const keys = Object.keys(value); const keys = Object.keys(value);
for (let i = 0; i < keys.length; i++) { for (let i = 0; i < keys.length; i++) {
const key = keys[i]; const key = keys[i];
cloned[key] = typeof value[key] !== "object" ? value[key] : deepClone(value[key], cache); cloned[key] = typeof value[key] !== "object" ? value[key] : deepClone(value[key], cache, allowCircle || key === "leadingComments" || key === "innerComments" || key === "trailingComments" || key === "extra");
} }
} }
if (!allowCircle) {
if (depth-- > 250) circleSet.delete(value);
}
return cloned; return cloned;
} }
return value; return value;
} }
function _default(value) { function _default(value) {
if (typeof value !== "object") return value; if (typeof value !== "object") return value;
return deepClone(value, new Map()); {
try {
return deepClone(value, new Map(), true);
} catch (_) {
return structuredClone(value);
}
}
} }
0 && 0; 0 && 0;

View File

@ -1 +1 @@
{"version":3,"names":["deepClone","value","cache","has","get","cloned","Array","isArray","length","set","i","keys","Object","key","_default","Map"],"sources":["../../../src/transformation/util/clone-deep.ts"],"sourcesContent":["//https://github.com/babel/babel/pull/14583#discussion_r882828856\nfunction deepClone(value: any, cache: Map<any, any>): any {\n if (value !== null) {\n if (cache.has(value)) return cache.get(value);\n let cloned: any;\n if (Array.isArray(value)) {\n cloned = new Array(value.length);\n cache.set(value, cloned);\n for (let i = 0; i < value.length; i++) {\n cloned[i] =\n typeof value[i] !== \"object\" ? value[i] : deepClone(value[i], cache);\n }\n } else {\n cloned = {};\n cache.set(value, cloned);\n const keys = Object.keys(value);\n for (let i = 0; i < keys.length; i++) {\n const key = keys[i];\n cloned[key] =\n typeof value[key] !== \"object\"\n ? value[key]\n : deepClone(value[key], cache);\n }\n }\n return cloned;\n }\n return value;\n}\n\nexport default function <T>(value: T): T {\n if (typeof value !== \"object\") return value;\n return deepClone(value, new Map());\n}\n"],"mappings":";;;;;;AACA,SAASA,SAASA,CAACC,KAAU,EAAEC,KAAoB,EAAO;EACxD,IAAID,KAAK,KAAK,IAAI,EAAE;IAClB,IAAIC,KAAK,CAACC,GAAG,CAACF,KAAK,CAAC,EAAE,OAAOC,KAAK,CAACE,GAAG,CAACH,KAAK,CAAC;IAC7C,IAAII,MAAW;IACf,IAAIC,KAAK,CAACC,OAAO,CAACN,KAAK,CAAC,EAAE;MACxBI,MAAM,GAAG,IAAIC,KAAK,CAACL,KAAK,CAACO,MAAM,CAAC;MAChCN,KAAK,CAACO,GAAG,CAACR,KAAK,EAAEI,MAAM,CAAC;MACxB,KAAK,IAAIK,CAAC,GAAG,CAAC,EAAEA,CAAC,GAAGT,KAAK,CAACO,MAAM,EAAEE,CAAC,EAAE,EAAE;QACrCL,MAAM,CAACK,CAAC,CAAC,GACP,OAAOT,KAAK,CAACS,CAAC,CAAC,KAAK,QAAQ,GAAGT,KAAK,CAACS,CAAC,CAAC,GAAGV,SAAS,CAACC,KAAK,CAACS,CAAC,CAAC,EAAER,KAAK,CAAC;MACxE;IACF,CAAC,MAAM;MACLG,MAAM,GAAG,CAAC,CAAC;MACXH,KAAK,CAACO,GAAG,CAACR,KAAK,EAAEI,MAAM,CAAC;MACxB,MAAMM,IAAI,GAAGC,MAAM,CAACD,IAAI,CAACV,KAAK,CAAC;MAC/B,KAAK,IAAIS,CAAC,GAAG,CAAC,EAAEA,CAAC,GAAGC,IAAI,CAACH,MAAM,EAAEE,CAAC,EAAE,EAAE;QACpC,MAAMG,GAAG,GAAGF,IAAI,CAACD,CAAC,CAAC;QACnBL,MAAM,CAACQ,GAAG,CAAC,GACT,OAAOZ,KAAK,CAACY,GAAG,CAAC,KAAK,QAAQ,GAC1BZ,KAAK,CAACY,GAAG,CAAC,GACVb,SAAS,CAACC,KAAK,CAACY,GAAG,CAAC,EAAEX,KAAK,CAAC;MACpC;IACF;IACA,OAAOG,MAAM;EACf;EACA,OAAOJ,KAAK;AACd;AAEe,SAAAa,SAAab,KAAQ,EAAK;EACvC,IAAI,OAAOA,KAAK,KAAK,QAAQ,EAAE,OAAOA,KAAK;EAC3C,OAAOD,SAAS,CAACC,KAAK,EAAE,IAAIc,GAAG,CAAC,CAAC,CAAC;AACpC;AAAC","ignoreList":[]} {"version":3,"names":["circleSet","Set","depth","deepClone","value","cache","allowCircle","has","get","clear","Error","add","cloned","Array","isArray","length","set","i","keys","Object","key","delete","_default","Map","_","structuredClone"],"sources":["../../../src/transformation/util/clone-deep.ts"],"sourcesContent":["const circleSet = new Set();\nlet depth = 0;\n// https://github.com/babel/babel/pull/14583#discussion_r882828856\nfunction deepClone(\n value: any,\n cache: Map<any, any>,\n allowCircle: boolean,\n): any {\n if (value !== null) {\n if (allowCircle) {\n if (cache.has(value)) return cache.get(value);\n } else if (++depth > 250) {\n if (circleSet.has(value)) {\n depth = 0;\n circleSet.clear();\n throw new Error(\"Babel-deepClone: Cycles are not allowed in AST\");\n }\n circleSet.add(value);\n }\n let cloned: any;\n if (Array.isArray(value)) {\n cloned = new Array(value.length);\n if (allowCircle) cache.set(value, cloned);\n for (let i = 0; i < value.length; i++) {\n cloned[i] =\n typeof value[i] !== \"object\"\n ? value[i]\n : deepClone(value[i], cache, allowCircle);\n }\n } else {\n cloned = {};\n if (allowCircle) cache.set(value, cloned);\n const keys = Object.keys(value);\n for (let i = 0; i < keys.length; i++) {\n const key = keys[i];\n cloned[key] =\n typeof value[key] !== \"object\"\n ? value[key]\n : deepClone(\n value[key],\n cache,\n allowCircle ||\n key === \"leadingComments\" ||\n key === \"innerComments\" ||\n key === \"trailingComments\" ||\n key === \"extra\",\n );\n }\n }\n if (!allowCircle) {\n if (depth-- > 250) circleSet.delete(value);\n }\n return cloned;\n }\n return value;\n}\n\nexport default function <T>(value: T): T {\n if (typeof value !== \"object\") return value;\n\n if (process.env.BABEL_8_BREAKING) {\n if (!process.env.IS_PUBLISH && depth > 0) {\n throw new Error(\"depth > 0\");\n }\n return deepClone(value, new Map(), false);\n } else {\n try {\n return deepClone(value, new Map(), true);\n } catch (_) {\n return structuredClone(value);\n }\n }\n}\n"],"mappings":";;;;;;AAAA,MAAMA,SAAS,GAAG,IAAIC,GAAG,CAAC,CAAC;AAC3B,IAAIC,KAAK,GAAG,CAAC;AAEb,SAASC,SAASA,CAChBC,KAAU,EACVC,KAAoB,EACpBC,WAAoB,EACf;EACL,IAAIF,KAAK,KAAK,IAAI,EAAE;IAClB,IAAIE,WAAW,EAAE;MACf,IAAID,KAAK,CAACE,GAAG,CAACH,KAAK,CAAC,EAAE,OAAOC,KAAK,CAACG,GAAG,CAACJ,KAAK,CAAC;IAC/C,CAAC,MAAM,IAAI,EAAEF,KAAK,GAAG,GAAG,EAAE;MACxB,IAAIF,SAAS,CAACO,GAAG,CAACH,KAAK,CAAC,EAAE;QACxBF,KAAK,GAAG,CAAC;QACTF,SAAS,CAACS,KAAK,CAAC,CAAC;QACjB,MAAM,IAAIC,KAAK,CAAC,gDAAgD,CAAC;MACnE;MACAV,SAAS,CAACW,GAAG,CAACP,KAAK,CAAC;IACtB;IACA,IAAIQ,MAAW;IACf,IAAIC,KAAK,CAACC,OAAO,CAACV,KAAK,CAAC,EAAE;MACxBQ,MAAM,GAAG,IAAIC,KAAK,CAACT,KAAK,CAACW,MAAM,CAAC;MAChC,IAAIT,WAAW,EAAED,KAAK,CAACW,GAAG,CAACZ,KAAK,EAAEQ,MAAM,CAAC;MACzC,KAAK,IAAIK,CAAC,GAAG,CAAC,EAAEA,CAAC,GAAGb,KAAK,CAACW,MAAM,EAAEE,CAAC,EAAE,EAAE;QACrCL,MAAM,CAACK,CAAC,CAAC,GACP,OAAOb,KAAK,CAACa,CAAC,CAAC,KAAK,QAAQ,GACxBb,KAAK,CAACa,CAAC,CAAC,GACRd,SAAS,CAACC,KAAK,CAACa,CAAC,CAAC,EAAEZ,KAAK,EAAEC,WAAW,CAAC;MAC/C;IACF,CAAC,MAAM;MACLM,MAAM,GAAG,CAAC,CAAC;MACX,IAAIN,WAAW,EAAED,KAAK,CAACW,GAAG,CAACZ,KAAK,EAAEQ,MAAM,CAAC;MACzC,MAAMM,IAAI,GAAGC,MAAM,CAACD,IAAI,CAACd,KAAK,CAAC;MAC/B,KAAK,IAAIa,CAAC,GAAG,CAAC,EAAEA,CAAC,GAAGC,IAAI,CAACH,MAAM,EAAEE,CAAC,EAAE,EAAE;QACpC,MAAMG,GAAG,GAAGF,IAAI,CAACD,CAAC,CAAC;QACnBL,MAAM,CAACQ,GAAG,CAAC,GACT,OAAOhB,KAAK,CAACgB,GAAG,CAAC,KAAK,QAAQ,GAC1BhB,KAAK,CAACgB,GAAG,CAAC,GACVjB,SAAS,CACPC,KAAK,CAACgB,GAAG,CAAC,EACVf,KAAK,EACLC,WAAW,IACTc,GAAG,KAAK,iBAAiB,IACzBA,GAAG,KAAK,eAAe,IACvBA,GAAG,KAAK,kBAAkB,IAC1BA,GAAG,KAAK,OACZ,CAAC;MACT;IACF;IACA,IAAI,CAACd,WAAW,EAAE;MAChB,IAAIJ,KAAK,EAAE,GAAG,GAAG,EAAEF,SAAS,CAACqB,MAAM,CAACjB,KAAK,CAAC;IAC5C;IACA,OAAOQ,MAAM;EACf;EACA,OAAOR,KAAK;AACd;AAEe,SAAAkB,SAAalB,KAAQ,EAAK;EACvC,IAAI,OAAOA,KAAK,KAAK,QAAQ,EAAE,OAAOA,KAAK;EAOpC;IACL,IAAI;MACF,OAAOD,SAAS,CAACC,KAAK,EAAE,IAAImB,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC;IAC1C,CAAC,CAAC,OAAOC,CAAC,EAAE;MACV,OAAOC,eAAe,CAACrB,KAAK,CAAC;IAC/B;EACF;AACF;AAAC","ignoreList":[]}

View File

@ -1,6 +1,6 @@
{ {
"name": "@babel/core", "name": "@babel/core",
"version": "7.26.9", "version": "7.26.10",
"description": "Babel compiler core.", "description": "Babel compiler core.",
"main": "./lib/index.js", "main": "./lib/index.js",
"author": "The Babel Team (https://babel.dev/team)", "author": "The Babel Team (https://babel.dev/team)",
@ -48,14 +48,14 @@
"dependencies": { "dependencies": {
"@ampproject/remapping": "^2.2.0", "@ampproject/remapping": "^2.2.0",
"@babel/code-frame": "^7.26.2", "@babel/code-frame": "^7.26.2",
"@babel/generator": "^7.26.9", "@babel/generator": "^7.26.10",
"@babel/helper-compilation-targets": "^7.26.5", "@babel/helper-compilation-targets": "^7.26.5",
"@babel/helper-module-transforms": "^7.26.0", "@babel/helper-module-transforms": "^7.26.0",
"@babel/helpers": "^7.26.9", "@babel/helpers": "^7.26.10",
"@babel/parser": "^7.26.9", "@babel/parser": "^7.26.10",
"@babel/template": "^7.26.9", "@babel/template": "^7.26.9",
"@babel/traverse": "^7.26.9", "@babel/traverse": "^7.26.10",
"@babel/types": "^7.26.9", "@babel/types": "^7.26.10",
"convert-source-map": "^2.0.0", "convert-source-map": "^2.0.0",
"debug": "^4.1.0", "debug": "^4.1.0",
"gensync": "^1.0.0-beta.2", "gensync": "^1.0.0-beta.2",

View File

@ -67,6 +67,7 @@ function ExportNamespaceSpecifier(node) {
} }
let warningShown = false; let warningShown = false;
function _printAttributes(node, hasPreviousBrace) { function _printAttributes(node, hasPreviousBrace) {
var _node$extra;
const { const {
importAttributesKeyword importAttributesKeyword
} = this.format; } = this.format;
@ -74,7 +75,7 @@ function _printAttributes(node, hasPreviousBrace) {
attributes, attributes,
assertions assertions
} = node; } = node;
if (attributes && !importAttributesKeyword && !warningShown) { if (attributes && !importAttributesKeyword && node.extra && (node.extra.deprecatedAssertSyntax || node.extra.deprecatedWithLegacySyntax) && !warningShown) {
warningShown = true; warningShown = true;
console.warn(`\ console.warn(`\
You are using import attributes, without specifying the desired output syntax. You are using import attributes, without specifying the desired output syntax.
@ -87,7 +88,7 @@ Please specify the "importAttributesKeyword" generator option, whose value can b
const useAssertKeyword = importAttributesKeyword === "assert" || !importAttributesKeyword && assertions; const useAssertKeyword = importAttributesKeyword === "assert" || !importAttributesKeyword && assertions;
this.word(useAssertKeyword ? "assert" : "with"); this.word(useAssertKeyword ? "assert" : "with");
this.space(); this.space();
if (!useAssertKeyword && importAttributesKeyword !== "with") { if (!useAssertKeyword && (importAttributesKeyword === "with-legacy" || !importAttributesKeyword && (_node$extra = node.extra) != null && _node$extra.deprecatedWithLegacySyntax)) {
this.printList(attributes || assertions); this.printList(attributes || assertions);
return; return;
} }

File diff suppressed because one or more lines are too long

View File

@ -688,7 +688,7 @@ function tsPrintClassMemberModifiers(node) {
this.word("static"); this.word("static");
this.space(); this.space();
} }
printModifiersList(this, node, [!isPrivateField && node.override && "override", !isPrivateField && node.abstract && "abstract", (isPublicField || isPrivateField) && node.readonly && "readonly"]); printModifiersList(this, node, [!isPrivateField && node.abstract && "abstract", !isPrivateField && node.override && "override", (isPublicField || isPrivateField) && node.readonly && "readonly"]);
} }
function printBraced(printer, node, cb) { function printBraced(printer, node, cb) {
printer.token("{"); printer.token("{");

File diff suppressed because one or more lines are too long

View File

@ -3,7 +3,8 @@
Object.defineProperty(exports, "__esModule", { Object.defineProperty(exports, "__esModule", {
value: true value: true
}); });
exports.default = generate; exports.default = void 0;
exports.generate = generate;
var _sourceMap = require("./source-map.js"); var _sourceMap = require("./source-map.js");
var _printer = require("./printer.js"); var _printer = require("./printer.js");
function normalizeOptions(code, opts, ast) { function normalizeOptions(code, opts, ast) {
@ -106,5 +107,6 @@ function generate(ast, opts = {}, code) {
const printer = new _printer.default(format, map, ast.tokens, typeof code === "string" ? code : null); const printer = new _printer.default(format, map, ast.tokens, typeof code === "string" ? code : null);
return printer.generate(ast); return printer.generate(ast);
} }
var _default = exports.default = generate;
//# sourceMappingURL=index.js.map //# sourceMappingURL=index.js.map

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,6 @@
{ {
"name": "@babel/generator", "name": "@babel/generator",
"version": "7.26.9", "version": "7.27.0",
"description": "Turns an AST into code.", "description": "Turns an AST into code.",
"author": "The Babel Team (https://babel.dev/team)", "author": "The Babel Team (https://babel.dev/team)",
"license": "MIT", "license": "MIT",
@ -19,16 +19,16 @@
"lib" "lib"
], ],
"dependencies": { "dependencies": {
"@babel/parser": "^7.26.9", "@babel/parser": "^7.27.0",
"@babel/types": "^7.26.9", "@babel/types": "^7.27.0",
"@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.25", "@jridgewell/trace-mapping": "^0.3.25",
"jsesc": "^3.0.2" "jsesc": "^3.0.2"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.26.9", "@babel/core": "^7.26.10",
"@babel/helper-fixtures": "^7.26.0", "@babel/helper-fixtures": "^7.26.0",
"@babel/plugin-transform-typescript": "^7.26.8", "@babel/plugin-transform-typescript": "^7.27.0",
"@jridgewell/sourcemap-codec": "^1.4.15", "@jridgewell/sourcemap-codec": "^1.4.15",
"@types/jsesc": "^2.5.0", "@types/jsesc": "^2.5.0",
"charcodes": "^0.2.0" "charcodes": "^0.2.0"

View File

@ -186,6 +186,7 @@ function getTargets(inputTargets = {}, options = {}) {
} }
} }
} }
;
if (esmodules && (esmodules !== "intersect" || !((_browsers = browsers) != null && _browsers.length))) { if (esmodules && (esmodules !== "intersect" || !((_browsers = browsers) != null && _browsers.length))) {
browsers = Object.keys(ESM_SUPPORT).map(browser => `${browser} >= ${ESM_SUPPORT[browser]}`).join(", "); browsers = Object.keys(ESM_SUPPORT).map(browser => `${browser} >= ${ESM_SUPPORT[browser]}`).join(", ");
esmodules = false; esmodules = false;

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,6 @@
{ {
"name": "@babel/helper-compilation-targets", "name": "@babel/helper-compilation-targets",
"version": "7.26.5", "version": "7.27.0",
"author": "The Babel Team (https://babel.dev/team)", "author": "The Babel Team (https://babel.dev/team)",
"license": "MIT", "license": "MIT",
"description": "Helper functions on Babel compilation targets", "description": "Helper functions on Babel compilation targets",
@ -25,7 +25,7 @@
"babel-plugin" "babel-plugin"
], ],
"dependencies": { "dependencies": {
"@babel/compat-data": "^7.26.5", "@babel/compat-data": "^7.26.8",
"@babel/helper-validator-option": "^7.25.9", "@babel/helper-validator-option": "^7.25.9",
"browserslist": "^4.24.0", "browserslist": "^4.24.0",
"lru-cache": "^5.1.1", "lru-cache": "^5.1.1",

View File

@ -369,15 +369,17 @@ function createPrivateBrandCheckClosure(brandName) {
return _core.types.arrowFunctionExpression([_core.types.identifier("_")], _core.types.binaryExpression("in", _core.types.cloneNode(brandName), _core.types.identifier("_"))); return _core.types.arrowFunctionExpression([_core.types.identifier("_")], _core.types.binaryExpression("in", _core.types.cloneNode(brandName), _core.types.identifier("_")));
} }
function usesPrivateField(expression) { function usesPrivateField(expression) {
try { {
_core.types.traverseFast(expression, node => { try {
if (_core.types.isPrivateName(node)) { _core.types.traverseFast(expression, node => {
throw null; if (_core.types.isPrivateName(node)) {
} throw null;
}); }
return false; });
} catch (_unused) { return false;
return true; } catch (_unused) {
return true;
}
} }
} }
function convertToComputedKey(path) { function convertToComputedKey(path) {
@ -430,7 +432,7 @@ function checkPrivateMethodUpdateError(path, decoratedPrivateMethods) {
}); });
} }
function transformClass(path, state, constantSuper, ignoreFunctionLength, className, propertyVisitor, version) { function transformClass(path, state, constantSuper, ignoreFunctionLength, className, propertyVisitor, version) {
var _path$node$id, _classDecorationsId; var _path$node$id;
const body = path.get("body.body"); const body = path.get("body.body");
const classDecorators = path.node.decorators; const classDecorators = path.node.decorators;
let hasElementDecorators = false; let hasElementDecorators = false;
@ -449,19 +451,21 @@ function transformClass(path, state, constantSuper, ignoreFunctionLength, classN
const classIdName = (_path$node$id = path.node.id) == null ? void 0 : _path$node$id.name; const classIdName = (_path$node$id = path.node.id) == null ? void 0 : _path$node$id.name;
const setClassName = typeof className === "object" ? className : undefined; const setClassName = typeof className === "object" ? className : undefined;
const usesFunctionContextOrYieldAwait = decorator => { const usesFunctionContextOrYieldAwait = decorator => {
try { {
_core.types.traverseFast(decorator, node => { try {
if (_core.types.isThisExpression(node) || _core.types.isSuper(node) || _core.types.isYieldExpression(node) || _core.types.isAwaitExpression(node) || _core.types.isIdentifier(node, { _core.types.traverseFast(decorator, node => {
name: "arguments" if (_core.types.isThisExpression(node) || _core.types.isSuper(node) || _core.types.isYieldExpression(node) || _core.types.isAwaitExpression(node) || _core.types.isIdentifier(node, {
}) || classIdName && _core.types.isIdentifier(node, { name: "arguments"
name: classIdName }) || classIdName && _core.types.isIdentifier(node, {
}) || _core.types.isMetaProperty(node) && node.meta.name !== "import") { name: classIdName
throw null; }) || _core.types.isMetaProperty(node) && node.meta.name !== "import") {
} throw null;
}); }
return false; });
} catch (_unused2) { return false;
return true; } catch (_unused2) {
return true;
}
} }
}; };
const instancePrivateNames = []; const instancePrivateNames = [];
@ -488,11 +492,9 @@ function transformClass(path, state, constantSuper, ignoreFunctionLength, classN
} }
default: default:
if (elementNode.static) { if (elementNode.static) {
var _staticInitLocal; staticInitLocal != null ? staticInitLocal : staticInitLocal = generateLetUidIdentifier(scopeParent, "initStatic");
(_staticInitLocal = staticInitLocal) != null ? _staticInitLocal : staticInitLocal = generateLetUidIdentifier(scopeParent, "initStatic");
} else { } else {
var _protoInitLocal; protoInitLocal != null ? protoInitLocal : protoInitLocal = generateLetUidIdentifier(scopeParent, "initProto");
(_protoInitLocal = protoInitLocal) != null ? _protoInitLocal : protoInitLocal = generateLetUidIdentifier(scopeParent, "initProto");
} }
break; break;
} }
@ -554,8 +556,7 @@ function transformClass(path, state, constantSuper, ignoreFunctionLength, classN
} else if (scopeParent.isStatic(expression.object)) { } else if (scopeParent.isStatic(expression.object)) {
object = _core.types.cloneNode(expression.object); object = _core.types.cloneNode(expression.object);
} else { } else {
var _decoratorReceiverId; decoratorReceiverId != null ? decoratorReceiverId : decoratorReceiverId = generateLetUidIdentifier(scopeParent, "obj");
(_decoratorReceiverId = decoratorReceiverId) != null ? _decoratorReceiverId : decoratorReceiverId = generateLetUidIdentifier(scopeParent, "obj");
object = _core.types.assignmentExpression("=", _core.types.cloneNode(decoratorReceiverId), expression.object); object = _core.types.assignmentExpression("=", _core.types.cloneNode(decoratorReceiverId), expression.object);
expression.object = _core.types.cloneNode(decoratorReceiverId); expression.object = _core.types.cloneNode(decoratorReceiverId);
} }
@ -993,7 +994,7 @@ function transformClass(path, state, constantSuper, ignoreFunctionLength, classN
} }
computedKeyAssignments = []; computedKeyAssignments = [];
} }
applyDecsBody.push(_core.types.expressionStatement(createLocalsAssignment(elementLocals, classLocals, elementDecorations, (_classDecorationsId = classDecorationsId) != null ? _classDecorationsId : _core.types.arrayExpression(classDecorations), _core.types.numericLiteral(classDecorationsFlag), needsInstancePrivateBrandCheck ? lastInstancePrivateName : null, setClassName, _core.types.cloneNode(superClass), state, version))); applyDecsBody.push(_core.types.expressionStatement(createLocalsAssignment(elementLocals, classLocals, elementDecorations, classDecorationsId != null ? classDecorationsId : _core.types.arrayExpression(classDecorations), _core.types.numericLiteral(classDecorationsFlag), needsInstancePrivateBrandCheck ? lastInstancePrivateName : null, setClassName, _core.types.cloneNode(superClass), state, version)));
if (staticInitLocal) { if (staticInitLocal) {
applyDecsBody.push(_core.types.expressionStatement(_core.types.callExpression(_core.types.cloneNode(staticInitLocal), [_core.types.thisExpression()]))); applyDecsBody.push(_core.types.expressionStatement(_core.types.callExpression(_core.types.cloneNode(staticInitLocal), [_core.types.thisExpression()])));
} }
@ -1265,12 +1266,12 @@ function _default({
const ignoreFunctionLength = (_assumption2 = assumption("ignoreFunctionLength")) != null ? _assumption2 : loose; const ignoreFunctionLength = (_assumption2 = assumption("ignoreFunctionLength")) != null ? _assumption2 : loose;
const namedEvaluationVisitor = NamedEvaluationVisitoryFactory(isDecoratedAnonymousClassExpression, visitClass); const namedEvaluationVisitor = NamedEvaluationVisitoryFactory(isDecoratedAnonymousClassExpression, visitClass);
function visitClass(path, state, className) { function visitClass(path, state, className) {
var _className, _node$id; var _node$id;
if (VISITED.has(path)) return; if (VISITED.has(path)) return;
const { const {
node node
} = path; } = path;
(_className = className) != null ? _className : className = (_node$id = node.id) == null ? void 0 : _node$id.name; className != null ? className : className = (_node$id = node.id) == null ? void 0 : _node$id.name;
const newPath = transformClass(path, state, constantSuper, ignoreFunctionLength, className, namedEvaluationVisitor, version); const newPath = transformClass(path, state, constantSuper, ignoreFunctionLength, className, namedEvaluationVisitor, version);
if (newPath) { if (newPath) {
VISITED.add(newPath); VISITED.add(newPath);

File diff suppressed because one or more lines are too long

View File

@ -38,9 +38,8 @@ function buildPrivateNamesMap(className, privateFieldsAsSymbolsOrProperties, pro
let initAdded = false; let initAdded = false;
let id; let id;
if (!privateFieldsAsSymbolsOrProperties && newHelpers(file) && isMethod && !isStatic) { if (!privateFieldsAsSymbolsOrProperties && newHelpers(file) && isMethod && !isStatic) {
var _classBrandId;
initAdded = !!classBrandId; initAdded = !!classBrandId;
(_classBrandId = classBrandId) != null ? _classBrandId : classBrandId = prop.scope.generateUidIdentifier(`${className}_brand`); classBrandId != null ? classBrandId : classBrandId = prop.scope.generateUidIdentifier(`${className}_brand`);
id = classBrandId; id = classBrandId;
} else { } else {
id = prop.scope.generateUidIdentifier(name); id = prop.scope.generateUidIdentifier(name);
@ -897,7 +896,6 @@ function inheritLoc(node, original) {
return node; return node;
} }
function buildFieldsInitNodes(ref, superRef, props, privateNamesMap, file, setPublicClassFields, privateFieldsAsSymbolsOrProperties, noUninitializedPrivateFieldAccess, constantSuper, innerBindingRef) { function buildFieldsInitNodes(ref, superRef, props, privateNamesMap, file, setPublicClassFields, privateFieldsAsSymbolsOrProperties, noUninitializedPrivateFieldAccess, constantSuper, innerBindingRef) {
var _ref, _ref2;
let classRefFlags = 0; let classRefFlags = 0;
let injectSuperRef; let injectSuperRef;
const staticNodes = []; const staticNodes = [];
@ -906,12 +904,11 @@ function buildFieldsInitNodes(ref, superRef, props, privateNamesMap, file, setPu
const pureStaticNodes = []; const pureStaticNodes = [];
let classBindingNode = null; let classBindingNode = null;
const getSuperRef = _core.types.isIdentifier(superRef) ? () => superRef : () => { const getSuperRef = _core.types.isIdentifier(superRef) ? () => superRef : () => {
var _injectSuperRef; injectSuperRef != null ? injectSuperRef : injectSuperRef = props[0].scope.generateUidIdentifierBasedOnNode(superRef);
(_injectSuperRef = injectSuperRef) != null ? _injectSuperRef : injectSuperRef = props[0].scope.generateUidIdentifierBasedOnNode(superRef);
return injectSuperRef; return injectSuperRef;
}; };
const classRefForInnerBinding = (_ref = ref) != null ? _ref : props[0].scope.generateUidIdentifier((innerBindingRef == null ? void 0 : innerBindingRef.name) || "Class"); const classRefForInnerBinding = ref != null ? ref : props[0].scope.generateUidIdentifier((innerBindingRef == null ? void 0 : innerBindingRef.name) || "Class");
(_ref2 = ref) != null ? _ref2 : ref = _core.types.cloneNode(innerBindingRef); ref != null ? ref : ref = _core.types.cloneNode(innerBindingRef);
for (const prop of props) { for (const prop of props) {
if (prop.isClassProperty()) { if (prop.isClassProperty()) {
ts.assertFieldTransformed(prop); ts.assertFieldTransformed(prop);

File diff suppressed because one or more lines are too long

View File

@ -57,8 +57,7 @@ function createClassFeaturePlugin({
} }
} }
{ {
var _api; api != null ? api : api = {
(_api = api) != null ? _api : api = {
assumption: () => void 0 assumption: () => void 0
}; };
} }
@ -95,20 +94,19 @@ function createClassFeaturePlugin({
(0, _features.enableFeature)(file, feature, loose); (0, _features.enableFeature)(file, feature, loose);
{ {
if (typeof file.get(versionKey) === "number") { if (typeof file.get(versionKey) === "number") {
file.set(versionKey, "7.26.9"); file.set(versionKey, "7.27.0");
return; return;
} }
} }
if (!file.get(versionKey) || _semver.lt(file.get(versionKey), "7.26.9")) { if (!file.get(versionKey) || _semver.lt(file.get(versionKey), "7.27.0")) {
file.set(versionKey, "7.26.9"); file.set(versionKey, "7.27.0");
} }
}, },
visitor: { visitor: {
Class(path, { Class(path, {
file file
}) { }) {
var _ref; if (file.get(versionKey) !== "7.27.0") return;
if (file.get(versionKey) !== "7.26.9") return;
if (!(0, _features.shouldTransform)(path, file)) return; if (!(0, _features.shouldTransform)(path, file)) return;
const pathIsClassDeclaration = path.isClassDeclaration(); const pathIsClassDeclaration = path.isClassDeclaration();
if (pathIsClassDeclaration) (0, _typescript.assertFieldTransformed)(path); if (pathIsClassDeclaration) (0, _typescript.assertFieldTransformed)(path);
@ -173,7 +171,7 @@ function createClassFeaturePlugin({
path.ensureFunctionName(false); path.ensureFunctionName(false);
ref = path.scope.generateUidIdentifier((innerBinding == null ? void 0 : innerBinding.name) || "Class"); ref = path.scope.generateUidIdentifier((innerBinding == null ? void 0 : innerBinding.name) || "Class");
} }
const classRefForDefine = (_ref = ref) != null ? _ref : _core.types.cloneNode(innerBinding); const classRefForDefine = ref != null ? ref : _core.types.cloneNode(innerBinding);
const privateNamesMap = (0, _fields.buildPrivateNamesMap)(classRefForDefine.name, privateFieldsAsSymbolsOrProperties != null ? privateFieldsAsSymbolsOrProperties : loose, props, file); const privateNamesMap = (0, _fields.buildPrivateNamesMap)(classRefForDefine.name, privateFieldsAsSymbolsOrProperties != null ? privateFieldsAsSymbolsOrProperties : loose, props, file);
const privateNamesNodes = (0, _fields.buildPrivateNamesNodes)(privateNamesMap, privateFieldsAsProperties != null ? privateFieldsAsProperties : loose, privateFieldsAsSymbols != null ? privateFieldsAsSymbols : false, file); const privateNamesNodes = (0, _fields.buildPrivateNamesNodes)(privateNamesMap, privateFieldsAsProperties != null ? privateFieldsAsProperties : loose, privateFieldsAsSymbols != null ? privateFieldsAsSymbols : false, file);
(0, _fields.transformPrivateNamesUsage)(classRefForDefine, path, privateNamesMap, { (0, _fields.transformPrivateNamesUsage)(classRefForDefine, path, privateNamesMap, {
@ -229,7 +227,7 @@ function createClassFeaturePlugin({
file file
}) { }) {
{ {
if (file.get(versionKey) !== "7.26.9") return; if (file.get(versionKey) !== "7.27.0") return;
const decl = path.get("declaration"); const decl = path.get("declaration");
if (decl.isClassDeclaration() && (0, _decorators.hasDecorators)(decl.node)) { if (decl.isClassDeclaration() && (0, _decorators.hasDecorators)(decl.node)) {
if (decl.node.id) { if (decl.node.id) {

File diff suppressed because one or more lines are too long

View File

@ -43,7 +43,10 @@ function handleClassTDZ(path, state) {
} }
} }
const classFieldDefinitionEvaluationTDZVisitor = { const classFieldDefinitionEvaluationTDZVisitor = {
ReferencedIdentifier: handleClassTDZ ReferencedIdentifier: handleClassTDZ,
"TSTypeAnnotation|TypeAnnotation"(path) {
path.skip();
}
}; };
function injectInitialization(path, constructor, nodes, renamer, lastReturnsThis) { function injectInitialization(path, constructor, nodes, renamer, lastReturnsThis) {
if (!nodes.length) return; if (!nodes.length) return;

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,6 @@
{ {
"name": "@babel/helper-create-class-features-plugin", "name": "@babel/helper-create-class-features-plugin",
"version": "7.26.9", "version": "7.27.0",
"author": "The Babel Team (https://babel.dev/team)", "author": "The Babel Team (https://babel.dev/team)",
"license": "MIT", "license": "MIT",
"description": "Compile class public and private fields, private methods and decorators to ES6", "description": "Compile class public and private fields, private methods and decorators to ES6",
@ -23,14 +23,14 @@
"@babel/helper-optimise-call-expression": "^7.25.9", "@babel/helper-optimise-call-expression": "^7.25.9",
"@babel/helper-replace-supers": "^7.26.5", "@babel/helper-replace-supers": "^7.26.5",
"@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9",
"@babel/traverse": "^7.26.9", "@babel/traverse": "^7.27.0",
"semver": "^6.3.1" "semver": "^6.3.1"
}, },
"peerDependencies": { "peerDependencies": {
"@babel/core": "^7.0.0" "@babel/core": "^7.0.0"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.26.9", "@babel/core": "^7.26.10",
"@babel/helper-plugin-test-runner": "^7.25.9", "@babel/helper-plugin-test-runner": "^7.25.9",
"@babel/preset-env": "^7.26.9", "@babel/preset-env": "^7.26.9",
"@types/charcodes": "^0.2.0", "@types/charcodes": "^0.2.0",

View File

@ -49,17 +49,17 @@ function createRegExpFeaturePlugin({
} }
{ {
if (typeof file.get(versionKey) === "number") { if (typeof file.get(versionKey) === "number") {
file.set(versionKey, "7.26.3"); file.set(versionKey, "7.27.0");
return; return;
} }
} }
if (!file.get(versionKey) || _semver.lt(file.get(versionKey), "7.26.3")) { if (!file.get(versionKey) || _semver.lt(file.get(versionKey), "7.27.0")) {
file.set(versionKey, "7.26.3"); file.set(versionKey, "7.27.0");
} }
}, },
visitor: { visitor: {
RegExpLiteral(path) { RegExpLiteral(path) {
var _file$get2, _newFlags; var _file$get2;
const { const {
node node
} = path; } = path;
@ -99,7 +99,7 @@ function createRegExpFeaturePlugin({
(0, _helperAnnotateAsPure.default)(call); (0, _helperAnnotateAsPure.default)(call);
path.replaceWith(call); path.replaceWith(call);
} }
node.flags = (0, _util.transformFlags)(regexpuOptions, (_newFlags = newFlags) != null ? _newFlags : node.flags); node.flags = (0, _util.transformFlags)(regexpuOptions, newFlags != null ? newFlags : node.flags);
} }
} }
}; };

File diff suppressed because one or more lines are too long

View File

@ -13,9 +13,9 @@ function generateRegexpuOptions(pattern, toTransform) {
}; };
const featDuplicateNamedGroups = () => { const featDuplicateNamedGroups = () => {
if (!feat("duplicateNamedCaptureGroups")) return false; if (!feat("duplicateNamedCaptureGroups")) return false;
const regex = /\(\?<([^>]+)>/g; const regex = /\(\?<([^>]+)(>|$)/g;
const seen = new Set(); const seen = new Set();
for (let match; match = regex.exec(pattern); seen.add(match[1])) { for (let match; (match = regex.exec(pattern)) && match[2]; seen.add(match[1])) {
if (seen.has(match[1])) return "transform"; if (seen.has(match[1])) return "transform";
} }
return false; return false;

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,6 @@
{ {
"name": "@babel/helper-create-regexp-features-plugin", "name": "@babel/helper-create-regexp-features-plugin",
"version": "7.26.3", "version": "7.27.0",
"author": "The Babel Team (https://babel.dev/team)", "author": "The Babel Team (https://babel.dev/team)",
"license": "MIT", "license": "MIT",
"description": "Compile ESNext Regular Expressions to ES5", "description": "Compile ESNext Regular Expressions to ES5",
@ -26,7 +26,7 @@
"@babel/core": "^7.0.0" "@babel/core": "^7.0.0"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.26.0", "@babel/core": "^7.26.10",
"@babel/helper-plugin-test-runner": "^7.25.9" "@babel/helper-plugin-test-runner": "^7.25.9"
}, },
"engines": { "engines": {

View File

@ -14,20 +14,28 @@ function intersection(a, b) {
function has$1(object, key) { function has$1(object, key) {
return Object.prototype.hasOwnProperty.call(object, key); return Object.prototype.hasOwnProperty.call(object, key);
} }
function getType(target) { function resolve$1(path, resolved = new Set()) {
return Object.prototype.toString.call(target).slice(8, -1); if (resolved.has(path)) return;
resolved.add(path);
if (path.isVariableDeclarator()) {
if (path.get("id").isIdentifier()) {
return resolve$1(path.get("init"), resolved);
}
} else if (path.isReferencedIdentifier()) {
const binding = path.scope.getBinding(path.node.name);
if (!binding) return path;
if (!binding.constant) return;
return resolve$1(binding.path, resolved);
}
return path;
} }
function resolveId(path) { function resolveId(path) {
if (path.isIdentifier() && !path.scope.hasBinding(path.node.name, /* noGlobals */true)) { if (path.isIdentifier() && !path.scope.hasBinding(path.node.name, /* noGlobals */true)) {
return path.node.name; return path.node.name;
} }
if (path.isPure()) { const resolved = resolve$1(path);
const { if (resolved != null && resolved.isIdentifier()) {
deopt return resolved.node.name;
} = path.evaluate();
if (deopt && deopt.isIdentifier()) {
return deopt.node.name;
}
} }
} }
function resolveKey(path, computed = false) { function resolveKey(path, computed = false) {
@ -75,26 +83,43 @@ function resolveSource(obj) {
placement: "static" placement: "static"
}; };
} }
if (obj.isRegExpLiteral()) { const path = resolve$1(obj);
return { switch (path == null ? void 0 : path.type) {
id: "RegExp", case "RegExpLiteral":
placement: "prototype"
};
} else if (obj.isFunction()) {
return {
id: "Function",
placement: "prototype"
};
} else if (obj.isPure()) {
const {
value
} = obj.evaluate();
if (value !== undefined) {
return { return {
id: getType(value), id: "RegExp",
placement: "prototype"
};
case "FunctionExpression":
return {
id: "Function",
placement: "prototype"
};
case "StringLiteral":
return {
id: "String",
placement: "prototype"
};
case "NumberLiteral":
return {
id: "Number",
placement: "prototype"
};
case "BooleanLiteral":
return {
id: "Boolean",
placement: "prototype"
};
case "ObjectExpression":
return {
id: "Object",
placement: "prototype"
};
case "ArrayExpression":
return {
id: "Array",
placement: "prototype" placement: "prototype"
}; };
}
} }
return { return {
id: null, id: null,

File diff suppressed because one or more lines are too long

View File

@ -18,20 +18,28 @@ function intersection(a, b) {
function has$1(object, key) { function has$1(object, key) {
return Object.prototype.hasOwnProperty.call(object, key); return Object.prototype.hasOwnProperty.call(object, key);
} }
function getType(target) { function resolve$1(path, resolved = new Set()) {
return Object.prototype.toString.call(target).slice(8, -1); if (resolved.has(path)) return;
resolved.add(path);
if (path.isVariableDeclarator()) {
if (path.get("id").isIdentifier()) {
return resolve$1(path.get("init"), resolved);
}
} else if (path.isReferencedIdentifier()) {
const binding = path.scope.getBinding(path.node.name);
if (!binding) return path;
if (!binding.constant) return;
return resolve$1(binding.path, resolved);
}
return path;
} }
function resolveId(path) { function resolveId(path) {
if (path.isIdentifier() && !path.scope.hasBinding(path.node.name, /* noGlobals */true)) { if (path.isIdentifier() && !path.scope.hasBinding(path.node.name, /* noGlobals */true)) {
return path.node.name; return path.node.name;
} }
if (path.isPure()) { const resolved = resolve$1(path);
const { if (resolved != null && resolved.isIdentifier()) {
deopt return resolved.node.name;
} = path.evaluate();
if (deopt && deopt.isIdentifier()) {
return deopt.node.name;
}
} }
} }
function resolveKey(path, computed = false) { function resolveKey(path, computed = false) {
@ -79,26 +87,43 @@ function resolveSource(obj) {
placement: "static" placement: "static"
}; };
} }
if (obj.isRegExpLiteral()) { const path = resolve$1(obj);
return { switch (path == null ? void 0 : path.type) {
id: "RegExp", case "RegExpLiteral":
placement: "prototype"
};
} else if (obj.isFunction()) {
return {
id: "Function",
placement: "prototype"
};
} else if (obj.isPure()) {
const {
value
} = obj.evaluate();
if (value !== undefined) {
return { return {
id: getType(value), id: "RegExp",
placement: "prototype"
};
case "FunctionExpression":
return {
id: "Function",
placement: "prototype"
};
case "StringLiteral":
return {
id: "String",
placement: "prototype"
};
case "NumberLiteral":
return {
id: "Number",
placement: "prototype"
};
case "BooleanLiteral":
return {
id: "Boolean",
placement: "prototype"
};
case "ObjectExpression":
return {
id: "Object",
placement: "prototype"
};
case "ArrayExpression":
return {
id: "Array",
placement: "prototype" placement: "prototype"
}; };
}
} }
return { return {
id: null, id: null,

File diff suppressed because one or more lines are too long

View File

@ -23,20 +23,28 @@ function intersection(a, b) {
function has(object, key) { function has(object, key) {
return Object.prototype.hasOwnProperty.call(object, key); return Object.prototype.hasOwnProperty.call(object, key);
} }
function getType(target) { function resolve(path, resolved = new Set()) {
return Object.prototype.toString.call(target).slice(8, -1); if (resolved.has(path)) return;
resolved.add(path);
if (path.isVariableDeclarator()) {
if (path.get("id").isIdentifier()) {
return resolve(path.get("init"), resolved);
}
} else if (path.isReferencedIdentifier()) {
const binding = path.scope.getBinding(path.node.name);
if (!binding) return path;
if (!binding.constant) return;
return resolve(binding.path, resolved);
}
return path;
} }
function resolveId(path) { function resolveId(path) {
if (path.isIdentifier() && !path.scope.hasBinding(path.node.name, /* noGlobals */true)) { if (path.isIdentifier() && !path.scope.hasBinding(path.node.name, /* noGlobals */true)) {
return path.node.name; return path.node.name;
} }
if (path.isPure()) { const resolved = resolve(path);
const { if (resolved != null && resolved.isIdentifier()) {
deopt return resolved.node.name;
} = path.evaluate();
if (deopt && deopt.isIdentifier()) {
return deopt.node.name;
}
} }
} }
function resolveKey(path, computed = false) { function resolveKey(path, computed = false) {
@ -84,26 +92,43 @@ function resolveSource(obj) {
placement: "static" placement: "static"
}; };
} }
if (obj.isRegExpLiteral()) { const path = resolve(obj);
return { switch (path == null ? void 0 : path.type) {
id: "RegExp", case "RegExpLiteral":
placement: "prototype"
};
} else if (obj.isFunction()) {
return {
id: "Function",
placement: "prototype"
};
} else if (obj.isPure()) {
const {
value
} = obj.evaluate();
if (value !== undefined) {
return { return {
id: getType(value), id: "RegExp",
placement: "prototype"
};
case "FunctionExpression":
return {
id: "Function",
placement: "prototype"
};
case "StringLiteral":
return {
id: "String",
placement: "prototype"
};
case "NumberLiteral":
return {
id: "Number",
placement: "prototype"
};
case "BooleanLiteral":
return {
id: "Boolean",
placement: "prototype"
};
case "ObjectExpression":
return {
id: "Object",
placement: "prototype"
};
case "ArrayExpression":
return {
id: "Array",
placement: "prototype" placement: "prototype"
}; };
}
} }
return { return {
id: null, id: null,

View File

@ -20,15 +20,18 @@ indent_size = 1
[package.json] [package.json]
indent_style = tab indent_style = tab
[lib/core.json]
indent_style = tab
[CHANGELOG.md] [CHANGELOG.md]
indent_style = space indent_style = space
indent_size = 2 indent_size = 2
[{*.json,Makefile}] [{*.json,Makefile}]
max_line_length = unset max_line_length = off
[test/{dotdot,resolver,module_dir,multirepo,node_path,pathfilter,precedence}/**/*] [test/{dotdot,resolver,module_dir,multirepo,node_path,pathfilter,precedence}/**/*]
indent_style = unset indent_style = off
indent_size = unset indent_size = off
max_line_length = unset max_line_length = off
insert_final_newline = unset insert_final_newline = off

View File

@ -15,7 +15,7 @@
"global-require": 1, "global-require": 1,
"id-length": [2, { "min": 1, "max": 40 }], "id-length": [2, { "min": 1, "max": 40 }],
"max-lines": [2, 350], "max-lines": [2, 350],
"max-lines-per-function": 1, "max-lines-per-function": 0,
"max-nested-callbacks": 0, "max-nested-callbacks": 0,
"max-params": 0, "max-params": 0,
"max-statements-per-line": [2, { "max": 2 }], "max-statements-per-line": [2, { "max": 2 }],

View File

@ -1,4 +1,6 @@
var async = require('./lib/async'); var async = require('./lib/async');
async.core = require('./lib/core');
async.isCore = require('./lib/is-core');
async.sync = require('./lib/sync'); async.sync = require('./lib/sync');
module.exports = async; module.exports = async;

View File

@ -44,7 +44,7 @@ var defaultRealpath = function realpath(x, cb) {
}; };
var maybeRealpath = function maybeRealpath(realpath, x, opts, cb) { var maybeRealpath = function maybeRealpath(realpath, x, opts, cb) {
if (!opts || !opts.preserveSymlinks) { if (opts && opts.preserveSymlinks === false) {
realpath(x, cb); realpath(x, cb);
} else { } else {
cb(null, x); cb(null, x);
@ -59,7 +59,7 @@ var defaultReadPackage = function defaultReadPackage(readFile, pkgfile, cb) {
var pkg = JSON.parse(body); var pkg = JSON.parse(body);
cb(null, pkg); cb(null, pkg);
} catch (jsonErr) { } catch (jsonErr) {
cb(jsonErr); cb(null);
} }
} }
}); });
@ -118,26 +118,12 @@ module.exports = function resolve(x, options, callback) {
opts, opts,
function (err, realStart) { function (err, realStart) {
if (err) cb(err); if (err) cb(err);
else validateBasedir(realStart); else init(realStart);
} }
); );
function validateBasedir(basedir) {
if (opts.basedir) {
var dirError = new TypeError('Provided basedir "' + basedir + '" is not a directory' + (opts.preserveSymlinks ? '' : ', or a symlink to a directory'));
dirError.code = 'INVALID_BASEDIR';
isDirectory(basedir, function (err, result) {
if (err) return cb(err);
if (!result) { return cb(dirError); }
validBasedir(basedir);
});
} else {
validBasedir(basedir);
}
}
var res; var res;
function validBasedir(basedir) { function init(basedir) {
if ((/^(?:\.\.?(?:\/|$)|\/|([A-Za-z]:)?[/\\])/).test(x)) { if ((/^(?:\.\.?(?:\/|$)|\/|([A-Za-z]:)?[/\\])/).test(x)) {
res = path.resolve(basedir, x); res = path.resolve(basedir, x);
if (x === '.' || x === '..' || x.slice(-1) === '/') res += '/'; if (x === '.' || x === '..' || x.slice(-1) === '/') res += '/';
@ -242,12 +228,12 @@ module.exports = function resolve(x, options, callback) {
if (!ex) return loadpkg(path.dirname(dir), cb); if (!ex) return loadpkg(path.dirname(dir), cb);
readPackage(readFile, pkgfile, function (err, pkgParam) { readPackage(readFile, pkgfile, function (err, pkgParam) {
if (err && !(err instanceof SyntaxError)) cb(err); if (err) cb(err);
var pkg = pkgParam; var pkg = pkgParam;
if (pkg && opts.packageFilter) { if (pkg && opts.packageFilter) {
pkg = opts.packageFilter(pkg, pkgfile, dir); pkg = opts.packageFilter(pkg, pkgfile);
} }
cb(null, pkg, dir); cb(null, pkg, dir);
}); });
@ -264,7 +250,7 @@ module.exports = function resolve(x, options, callback) {
} }
maybeRealpath(realpath, x, opts, function (unwrapErr, pkgdir) { maybeRealpath(realpath, x, opts, function (unwrapErr, pkgdir) {
if (unwrapErr) return loadAsDirectory(path.dirname(x), fpkg, cb); if (unwrapErr) return cb(unwrapErr);
var pkgfile = path.join(pkgdir, 'package.json'); var pkgfile = path.join(pkgdir, 'package.json');
isFile(pkgfile, function (err, ex) { isFile(pkgfile, function (err, ex) {
if (err) return cb(err); if (err) return cb(err);
@ -276,7 +262,7 @@ module.exports = function resolve(x, options, callback) {
var pkg = pkgParam; var pkg = pkgParam;
if (pkg && opts.packageFilter) { if (pkg && opts.packageFilter) {
pkg = opts.packageFilter(pkg, pkgfile, pkgdir); pkg = opts.packageFilter(pkg, pkgfile);
} }
if (pkg && pkg.main) { if (pkg && pkg.main) {
@ -297,13 +283,7 @@ module.exports = function resolve(x, options, callback) {
loadAsDirectory(dir, pkg, function (err, n, pkg) { loadAsDirectory(dir, pkg, function (err, n, pkg) {
if (err) return cb(err); if (err) return cb(err);
if (n) return cb(null, n, pkg); if (n) return cb(null, n, pkg);
loadAsFile(path.join(x, 'index'), pkg, function (err, m, pkg) { loadAsFile(path.join(x, 'index'), pkg, cb);
if (err) return cb(err);
if (m) return cb(null, m, pkg);
var incorrectMainError = new Error("Cannot find module '" + path.resolve(x, pkg.main) + "'. Please verify that the package.json has a valid \"main\" entry");
incorrectMainError.code = 'INCORRECT_PACKAGE_MAIN';
return cb(incorrectMainError);
});
}); });
}); });
return; return;

View File

@ -48,14 +48,18 @@ var defaultRealpathSync = function realpathSync(x) {
}; };
var maybeRealpathSync = function maybeRealpathSync(realpathSync, x, opts) { var maybeRealpathSync = function maybeRealpathSync(realpathSync, x, opts) {
if (!opts || !opts.preserveSymlinks) { if (opts && opts.preserveSymlinks === false) {
return realpathSync(x); return realpathSync(x);
} }
return x; return x;
}; };
var defaultReadPackageSync = function defaultReadPackageSync(readFileSync, pkgfile) { var defaultReadPackageSync = function defaultReadPackageSync(readFileSync, pkgfile) {
return JSON.parse(readFileSync(pkgfile)); var body = readFileSync(pkgfile);
try {
var pkg = JSON.parse(body);
return pkg;
} catch (jsonErr) {}
}; };
var getPackageCandidates = function getPackageCandidates(x, start, opts) { var getPackageCandidates = function getPackageCandidates(x, start, opts) {
@ -73,8 +77,8 @@ module.exports = function resolveSync(x, options) {
var opts = normalizeOptions(x, options); var opts = normalizeOptions(x, options);
var isFile = opts.isFile || defaultIsFile; var isFile = opts.isFile || defaultIsFile;
var isDirectory = opts.isDirectory || defaultIsDir;
var readFileSync = opts.readFileSync || fs.readFileSync; var readFileSync = opts.readFileSync || fs.readFileSync;
var isDirectory = opts.isDirectory || defaultIsDir;
var realpathSync = opts.realpathSync || defaultRealpathSync; var realpathSync = opts.realpathSync || defaultRealpathSync;
var readPackageSync = opts.readPackageSync || defaultReadPackageSync; var readPackageSync = opts.readPackageSync || defaultReadPackageSync;
if (opts.readFileSync && opts.readPackageSync) { if (opts.readFileSync && opts.readPackageSync) {
@ -92,12 +96,6 @@ module.exports = function resolveSync(x, options) {
// ensure that `basedir` is an absolute path at this point, resolving against the process' current working directory // ensure that `basedir` is an absolute path at this point, resolving against the process' current working directory
var absoluteStart = maybeRealpathSync(realpathSync, path.resolve(basedir), opts); var absoluteStart = maybeRealpathSync(realpathSync, path.resolve(basedir), opts);
if (opts.basedir && !isDirectory(absoluteStart)) {
var dirError = new TypeError('Provided basedir "' + opts.basedir + '" is not a directory' + (opts.preserveSymlinks ? '' : ', or a symlink to a directory'));
dirError.code = 'INVALID_BASEDIR';
throw dirError;
}
if ((/^(?:\.\.?(?:\/|$)|\/|([A-Za-z]:)?[/\\])/).test(x)) { if ((/^(?:\.\.?(?:\/|$)|\/|([A-Za-z]:)?[/\\])/).test(x)) {
var res = path.resolve(absoluteStart, x); var res = path.resolve(absoluteStart, x);
if (x === '.' || x === '..' || x.slice(-1) === '/') res += '/'; if (x === '.' || x === '..' || x.slice(-1) === '/') res += '/';
@ -144,37 +142,32 @@ module.exports = function resolveSync(x, options) {
} }
if ((/[/\\]node_modules[/\\]*$/).test(dir)) return; if ((/[/\\]node_modules[/\\]*$/).test(dir)) return;
var pkgfile = path.join(isDirectory(dir) ? maybeRealpathSync(realpathSync, dir, opts) : dir, 'package.json'); var pkgfile = path.join(maybeRealpathSync(realpathSync, dir, opts), 'package.json');
if (!isFile(pkgfile)) { if (!isFile(pkgfile)) {
return loadpkg(path.dirname(dir)); return loadpkg(path.dirname(dir));
} }
var pkg; var pkg = readPackageSync(readFileSync, pkgfile);
try {
pkg = readPackageSync(readFileSync, pkgfile);
} catch (e) {
if (!(e instanceof SyntaxError)) {
throw e;
}
}
if (pkg && opts.packageFilter) { if (pkg && opts.packageFilter) {
pkg = opts.packageFilter(pkg, pkgfile, dir); // v2 will pass pkgfile
pkg = opts.packageFilter(pkg, /*pkgfile,*/ dir); // eslint-disable-line spaced-comment
} }
return { pkg: pkg, dir: dir }; return { pkg: pkg, dir: dir };
} }
function loadAsDirectorySync(x) { function loadAsDirectorySync(x) {
var pkgfile = path.join(isDirectory(x) ? maybeRealpathSync(realpathSync, x, opts) : x, '/package.json'); var pkgfile = path.join(maybeRealpathSync(realpathSync, x, opts), '/package.json');
if (isFile(pkgfile)) { if (isFile(pkgfile)) {
try { try {
var pkg = readPackageSync(readFileSync, pkgfile); var pkg = readPackageSync(readFileSync, pkgfile);
} catch (e) {} } catch (e) {}
if (pkg && opts.packageFilter) { if (pkg && opts.packageFilter) {
pkg = opts.packageFilter(pkg, pkgfile, x); // v2 will pass pkgfile
pkg = opts.packageFilter(pkg, /*pkgfile,*/ x); // eslint-disable-line spaced-comment
} }
if (pkg && pkg.main) { if (pkg && pkg.main) {
@ -187,17 +180,11 @@ module.exports = function resolveSync(x, options) {
pkg.main = 'index'; pkg.main = 'index';
} }
try { try {
var mainPath = path.resolve(x, pkg.main); var m = loadAsFileSync(path.resolve(x, pkg.main));
var m = loadAsFileSync(mainPath);
if (m) return m; if (m) return m;
var n = loadAsDirectorySync(mainPath); var n = loadAsDirectorySync(path.resolve(x, pkg.main));
if (n) return n; if (n) return n;
var checkIndex = loadAsFileSync(path.resolve(x, 'index')); } catch (e) {}
if (checkIndex) return checkIndex;
} catch (e) { }
var incorrectMainError = new Error("Cannot find module '" + path.resolve(x, pkg.main) + "'. Please verify that the package.json has a valid \"main\" entry");
incorrectMainError.code = 'INCORRECT_PACKAGE_MAIN';
throw incorrectMainError;
} }
} }

View File

@ -1,7 +1,7 @@
{ {
"name": "resolve", "name": "resolve",
"description": "resolve like require.resolve() on behalf of files asynchronously and synchronously", "description": "resolve like require.resolve() on behalf of files asynchronously and synchronously",
"version": "2.0.0-next.5", "version": "1.22.10",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git://github.com/browserify/resolve.git" "url": "git://github.com/browserify/resolve.git"
@ -10,18 +10,6 @@
"resolve": "./bin/resolve" "resolve": "./bin/resolve"
}, },
"main": "index.js", "main": "index.js",
"exports": {
".": [
{
"import": "./index.mjs",
"default": "./index.js"
},
"./index.js"
],
"./sync": "./lib/sync.js",
"./async": "./lib/async.js",
"./package.json": "./package.json"
},
"keywords": [ "keywords": [
"resolve", "resolve",
"require", "require",
@ -29,7 +17,7 @@
"module" "module"
], ],
"scripts": { "scripts": {
"prepack": "npmignore --auto --commentLines=autogenerated", "prepack": "npmignore --auto --commentLines=autogenerated && cp node_modules/is-core-module/core.json ./lib/ ||:",
"prepublishOnly": "safe-publish-latest", "prepublishOnly": "safe-publish-latest",
"prepublish": "not-in-publish || npm run prepublishOnly", "prepublish": "not-in-publish || npm run prepublishOnly",
"prelint": "eclint check $(git ls-files | xargs find 2> /dev/null | grep -vE 'node_modules|\\.git')", "prelint": "eclint check $(git ls-files | xargs find 2> /dev/null | grep -vE 'node_modules|\\.git')",
@ -38,25 +26,25 @@
"tests-only": "tape test/*.js", "tests-only": "tape test/*.js",
"pretest": "npm run lint", "pretest": "npm run lint",
"test": "npm run --silent tests-only", "test": "npm run --silent tests-only",
"posttest": "npm run test:multirepo && aud --production", "posttest": "npm run test:multirepo && npx npm@'>= 10.2' audit --production",
"test:multirepo": "cd ./test/resolver/multirepo && npm install && npm test" "test:multirepo": "cd ./test/resolver/multirepo && npm install && npm test"
}, },
"devDependencies": { "devDependencies": {
"@ljharb/eslint-config": "^21.1.0", "@ljharb/eslint-config": "^21.1.1",
"array.prototype.map": "^1.0.6", "array.prototype.map": "^1.0.7",
"aud": "^2.0.3",
"copy-dir": "^1.3.0", "copy-dir": "^1.3.0",
"eclint": "^2.8.1", "eclint": "^2.8.1",
"eslint": "=8.8.0", "eslint": "=8.8.0",
"in-publish": "^2.0.1", "in-publish": "^2.0.1",
"mkdirp": "^0.5.5", "mkdirp": "^0.5.5",
"mv": "^2.1.1", "mv": "^2.1.1",
"npmignore": "^0.3.0", "npmignore": "^0.3.1",
"object-keys": "^1.1.1", "object-keys": "^1.1.1",
"rimraf": "^2.7.1", "rimraf": "^2.7.1",
"safe-publish-latest": "^2.0.0", "safe-publish-latest": "^2.0.0",
"tap": "^0.4.13", "semver": "^6.3.1",
"tape": "^5.7.0", "tap": "0.4.13",
"tape": "^5.9.0",
"tmp": "^0.0.31" "tmp": "^0.0.31"
}, },
"license": "MIT", "license": "MIT",
@ -69,7 +57,7 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
}, },
"dependencies": { "dependencies": {
"is-core-module": "^2.13.0", "is-core-module": "^2.16.0",
"path-parse": "^1.0.7", "path-parse": "^1.0.7",
"supports-preserve-symlinks-flag": "^1.0.0" "supports-preserve-symlinks-flag": "^1.0.0"
}, },
@ -77,7 +65,11 @@
"ignore": [ "ignore": [
".github/workflows", ".github/workflows",
"appveyor.yml", "appveyor.yml",
"test/resolver/malformed_package_json" "test/resolver/malformed_package_json",
"test/list-exports"
] ]
},
"engines": {
"node": ">= 0.4"
} }
} }

View File

@ -80,7 +80,7 @@ options are:
* `opts.readPackage(readFile, pkgfile, cb)` - function to asynchronously read and parse a package.json file * `opts.readPackage(readFile, pkgfile, cb)` - function to asynchronously read and parse a package.json file
* readFile - the passed `opts.readFile` or `fs.readFile` if not specified * readFile - the passed `opts.readFile` or `fs.readFile` if not specified
* pkgfile - path to package.json * pkgfile - path to package.json
* cb - callback. a SyntaxError error argument will be ignored, all other error arguments will be treated as an error. * cb - callback
* `opts.packageFilter(pkg, pkgfile, dir)` - transform the parsed package.json contents before looking at the "main" field * `opts.packageFilter(pkg, pkgfile, dir)` - transform the parsed package.json contents before looking at the "main" field
* pkg - package data * pkg - package data
@ -111,6 +111,8 @@ options are:
* opts.preserveSymlinks - if true, doesn't resolve `basedir` to real path before resolving. * opts.preserveSymlinks - if true, doesn't resolve `basedir` to real path before resolving.
This is the way Node resolves dependencies when executed with the [--preserve-symlinks](https://nodejs.org/api/all.html#cli_preserve_symlinks) flag. This is the way Node resolves dependencies when executed with the [--preserve-symlinks](https://nodejs.org/api/all.html#cli_preserve_symlinks) flag.
**Note:** this property is currently `true` by default but it will be changed to
`false` in the next major version because *Node's resolution algorithm does not preserve symlinks by default*.
default `opts` values: default `opts` values:
@ -154,13 +156,13 @@ default `opts` values:
var pkg = JSON.parse(body); var pkg = JSON.parse(body);
cb(null, pkg); cb(null, pkg);
} catch (jsonErr) { } catch (jsonErr) {
cb(jsonErr); cb(null);
} }
} }
}); });
}, },
moduleDirectory: 'node_modules', moduleDirectory: 'node_modules',
preserveSymlinks: false preserveSymlinks: true
} }
``` ```
@ -185,14 +187,13 @@ options are:
* opts.realpathSync - function to synchronously resolve a potential symlink to its real path * opts.realpathSync - function to synchronously resolve a potential symlink to its real path
* `opts.readPackageSync(readFileSync, pkgfile)` - function to synchronously read and parse a package.json file. a thrown SyntaxError will be ignored, all other exceptions will propagate. * `opts.readPackageSync(readFileSync, pkgfile)` - function to synchronously read and parse a package.json file
* readFileSync - the passed `opts.readFileSync` or `fs.readFileSync` if not specified * readFileSync - the passed `opts.readFileSync` or `fs.readFileSync` if not specified
* pkgfile - path to package.json * pkgfile - path to package.json
* `opts.packageFilter(pkg, pkgfile, dir)` - transform the parsed package.json contents before looking at the "main" field * `opts.packageFilter(pkg, dir)` - transform the parsed package.json contents before looking at the "main" field
* pkg - package data * pkg - package data
* pkgfile - path to package.json * dir - directory that contains package.json (Note: the second argument will change to "pkgfile" in v2)
* dir - directory that contains package.json
* `opts.pathFilter(pkg, path, relativePath)` - transform a path within a package * `opts.pathFilter(pkg, path, relativePath)` - transform a path within a package
* pkg - package data * pkg - package data
@ -218,6 +219,8 @@ options are:
* opts.preserveSymlinks - if true, doesn't resolve `basedir` to real path before resolving. * opts.preserveSymlinks - if true, doesn't resolve `basedir` to real path before resolving.
This is the way Node resolves dependencies when executed with the [--preserve-symlinks](https://nodejs.org/api/all.html#cli_preserve_symlinks) flag. This is the way Node resolves dependencies when executed with the [--preserve-symlinks](https://nodejs.org/api/all.html#cli_preserve_symlinks) flag.
**Note:** this property is currently `true` by default but it will be changed to
`false` in the next major version because *Node's resolution algorithm does not preserve symlinks by default*.
default `opts` values: default `opts` values:
@ -258,10 +261,14 @@ default `opts` values:
return file; return file;
}, },
readPackageSync: function defaultReadPackageSync(readFileSync, pkgfile) { readPackageSync: function defaultReadPackageSync(readFileSync, pkgfile) {
return JSON.parse(readFileSync(pkgfile)); var body = readFileSync(pkgfile);
try {
var pkg = JSON.parse(body);
return pkg;
} catch (jsonErr) {}
}, },
moduleDirectory: 'node_modules', moduleDirectory: 'node_modules',
preserveSymlinks: false preserveSymlinks: true
} }
``` ```

View File

@ -0,0 +1,2 @@
var x = require('..');
console.log(x);

View File

@ -0,0 +1 @@
module.exports = 'whatever';

View File

@ -23,7 +23,7 @@ test('non-existent basedir should not throw when preserveSymlinks is false', fun
var module = './dotdot/abc'; var module = './dotdot/abc';
resolve(module, opts, function (err, res) { resolve(module, opts, function (err, res) {
t.equal(err.code, 'INVALID_BASEDIR'); t.equal(err.code, 'MODULE_NOT_FOUND');
t.equal(res, undefined); t.equal(res, undefined);
}); });
}); });

View File

@ -3,14 +3,14 @@ var test = require('tape');
var resolve = require('../'); var resolve = require('../');
test('filter', function (t) { test('filter', function (t) {
t.plan(5); t.plan(4);
var dir = path.join(__dirname, 'resolver'); var dir = path.join(__dirname, 'resolver');
var packageFilterArgs; var packageFilterArgs;
resolve('./baz', { resolve('./baz', {
basedir: dir, basedir: dir,
packageFilter: function (pkg, pkgfile, dir) { packageFilter: function (pkg, pkgfile) {
pkg.main = 'doom'; // eslint-disable-line no-param-reassign pkg.main = 'doom'; // eslint-disable-line no-param-reassign
packageFilterArgs = [pkg, pkgfile, dir]; packageFilterArgs = [pkg, pkgfile];
return pkg; return pkg;
} }
}, function (err, res, pkg) { }, function (err, res, pkg) {
@ -29,9 +29,6 @@ test('filter', function (t) {
'second packageFilter argument is "pkgfile"' 'second packageFilter argument is "pkgfile"'
); );
var packageFileDir = packageFilterArgs[2];
t.equal(packageFileDir, path.join(dir, 'baz'), 'third packageFilter argument is "dir"');
t.end(); t.end();
}); });
}); });

View File

@ -0,0 +1,33 @@
var path = require('path');
var test = require('tape');
var resolve = require('../');
test('filter', function (t) {
var dir = path.join(__dirname, 'resolver');
var packageFilterArgs;
var res = resolve.sync('./baz', {
basedir: dir,
// NOTE: in v2.x, this will be `pkg, pkgfile, dir`, but must remain "broken" here in v1.x for compatibility
packageFilter: function (pkg, /*pkgfile,*/ dir) { // eslint-disable-line spaced-comment
pkg.main = 'doom'; // eslint-disable-line no-param-reassign
packageFilterArgs = 'is 1.x' ? [pkg, dir] : [pkg, pkgfile, dir]; // eslint-disable-line no-constant-condition, no-undef
return pkg;
}
});
t.equal(res, path.join(dir, 'baz/doom.js'), 'changing the package "main" works');
var packageData = packageFilterArgs[0];
t.equal(packageData.main, 'doom', 'package "main" was altered');
if (!'is 1.x') { // eslint-disable-line no-constant-condition
var packageFile = packageFilterArgs[1];
t.equal(packageFile, path.join(dir, 'baz', 'package.json'), 'package.json path is correct');
}
var packageDir = packageFilterArgs['is 1.x' ? 1 : 2]; // eslint-disable-line no-constant-condition
// eslint-disable-next-line no-constant-condition
t.equal(packageDir, path.join(dir, 'baz'), ('is 1.x' ? 'second' : 'third') + ' packageFilter argument is "dir"');
t.end();
});

View File

@ -10,7 +10,6 @@ test('mock', function (t) {
var dirs = {}; var dirs = {};
dirs[path.resolve('/foo/bar')] = true; dirs[path.resolve('/foo/bar')] = true;
dirs[path.resolve('/foo/node_modules')] = true;
function opts(basedir) { function opts(basedir) {
return { return {

Some files were not shown because too many files have changed in this diff Show More