@lexical/compiler 0.0.0-bootstrap.0 → 0.49.1-nightly.20260901.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +228 -2
- package/dist/LexicalCompiler.dev.js +1725 -0
- package/dist/LexicalCompiler.dev.mjs +1704 -0
- package/dist/LexicalCompiler.js +11 -0
- package/dist/LexicalCompiler.js.flow +32 -0
- package/dist/LexicalCompiler.mjs +17 -0
- package/dist/LexicalCompiler.node.mjs +15 -0
- package/dist/LexicalCompiler.prod.js +9 -0
- package/dist/LexicalCompiler.prod.mjs +9 -0
- package/dist/LexicalCompilerPureAnnotations.dev.js +1725 -0
- package/dist/LexicalCompilerPureAnnotations.dev.mjs +1704 -0
- package/dist/LexicalCompilerPureAnnotations.js +11 -0
- package/dist/LexicalCompilerPureAnnotations.js.flow +78 -0
- package/dist/LexicalCompilerPureAnnotations.mjs +17 -0
- package/dist/LexicalCompilerPureAnnotations.node.mjs +15 -0
- package/dist/LexicalCompilerPureAnnotations.prod.js +9 -0
- package/dist/LexicalCompilerPureAnnotations.prod.mjs +9 -0
- package/dist/PureAnnotations.d.ts +172 -0
- package/dist/index.d.ts +8 -0
- package/dist/passes/pureAnnotations.d.mts +246 -0
- package/dist/typescript-too-old.d.ts +18 -0
- package/package.json +111 -6
- package/src/PureAnnotations.ts +206 -0
- package/src/index.ts +12 -0
- package/src/passes/pureAnnotations.mjs +1618 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict'
|
|
10
|
+
const LexicalCompilerPureAnnotations = process.env.NODE_ENV !== 'production' ? require('./LexicalCompilerPureAnnotations.dev.js') : require('./LexicalCompilerPureAnnotations.prod.js');
|
|
11
|
+
module.exports = LexicalCompilerPureAnnotations;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @flow strict
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* LexicalCompilerPureAnnotations
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
export type PureAnnotationsSourceMap = {
|
|
15
|
+
file?: string,
|
|
16
|
+
mappings: string,
|
|
17
|
+
names: Array<string>,
|
|
18
|
+
sources: Array<string>,
|
|
19
|
+
sourcesContent?: Array<string | null>,
|
|
20
|
+
version: number,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export type TransformPureAnnotationsOptions = {
|
|
24
|
+
filename?: string,
|
|
25
|
+
functions?: Iterable<string>,
|
|
26
|
+
inline?: boolean,
|
|
27
|
+
namespaces?: Iterable<string>,
|
|
28
|
+
parserPlugins?: ReadonlyArray<unknown>,
|
|
29
|
+
relativeImports?: boolean,
|
|
30
|
+
sourceMap?: boolean,
|
|
31
|
+
sources?: RegExp | ReadonlyArray<RegExp>,
|
|
32
|
+
strict?: boolean,
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export type PureAnnotationsResult = {
|
|
36
|
+
code: string,
|
|
37
|
+
count: number,
|
|
38
|
+
inlined: number,
|
|
39
|
+
map?: PureAnnotationsSourceMap,
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export type PureAnnotationsOptions = {
|
|
43
|
+
...TransformPureAnnotationsOptions,
|
|
44
|
+
enforce?: 'post' | 'pre',
|
|
45
|
+
exclude?: RegExp | ReadonlyArray<RegExp>,
|
|
46
|
+
include?: RegExp | ReadonlyArray<RegExp>,
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* The structural shape of the returned plugin, assignable to Vite's and
|
|
51
|
+
* Rollup's `Plugin`.
|
|
52
|
+
*/
|
|
53
|
+
export type PureAnnotationsPlugin = {
|
|
54
|
+
enforce?: 'post' | 'pre',
|
|
55
|
+
name: string,
|
|
56
|
+
transform(
|
|
57
|
+
code: string,
|
|
58
|
+
id: string,
|
|
59
|
+
): {code: string, map: PureAnnotationsSourceMap | null} | null,
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
declare export var PURE_FACTORY_FUNCTIONS: ReadonlyArray<string>;
|
|
63
|
+
declare export var PURE_NAMESPACES: ReadonlyArray<string>;
|
|
64
|
+
declare export var INLINE_FACTORY_FORMS: ReadonlyMap<string, string>;
|
|
65
|
+
|
|
66
|
+
declare export function transformPureAnnotations(
|
|
67
|
+
code: string,
|
|
68
|
+
options?: TransformPureAnnotationsOptions,
|
|
69
|
+
): PureAnnotationsResult | null;
|
|
70
|
+
|
|
71
|
+
declare export function pureCallNames(
|
|
72
|
+
code: string,
|
|
73
|
+
options?: TransformPureAnnotationsOptions,
|
|
74
|
+
): {functions: ReadonlySet<string>, namespaces: ReadonlySet<string>};
|
|
75
|
+
|
|
76
|
+
declare export function pureAnnotations(
|
|
77
|
+
options?: PureAnnotationsOptions,
|
|
78
|
+
): PureAnnotationsPlugin;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import * as modDev from './LexicalCompilerPureAnnotations.dev.mjs';
|
|
10
|
+
import * as modProd from './LexicalCompilerPureAnnotations.prod.mjs';
|
|
11
|
+
const mod = process.env.NODE_ENV !== 'production' ? modDev : modProd;
|
|
12
|
+
export const INLINE_FACTORY_FORMS = mod.INLINE_FACTORY_FORMS;
|
|
13
|
+
export const PURE_FACTORY_FUNCTIONS = mod.PURE_FACTORY_FUNCTIONS;
|
|
14
|
+
export const PURE_NAMESPACES = mod.PURE_NAMESPACES;
|
|
15
|
+
export const pureAnnotations = mod.pureAnnotations;
|
|
16
|
+
export const pureCallNames = mod.pureCallNames;
|
|
17
|
+
export const transformPureAnnotations = mod.transformPureAnnotations;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const mod = await (process.env.NODE_ENV !== 'production' ? import('./LexicalCompilerPureAnnotations.dev.mjs') : import('./LexicalCompilerPureAnnotations.prod.mjs'));
|
|
10
|
+
export const INLINE_FACTORY_FORMS = mod.INLINE_FACTORY_FORMS;
|
|
11
|
+
export const PURE_FACTORY_FUNCTIONS = mod.PURE_FACTORY_FUNCTIONS;
|
|
12
|
+
export const PURE_NAMESPACES = mod.PURE_NAMESPACES;
|
|
13
|
+
export const pureAnnotations = mod.pureAnnotations;
|
|
14
|
+
export const pureCallNames = mod.pureCallNames;
|
|
15
|
+
export const transformPureAnnotations = mod.transformPureAnnotations;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
"use strict";var e=require("@babel/parser"),t=require("magic-string"),n=require("node:fs"),r=require("node:path");function o(e){var t=Object.create(null);if(e)for(var n in e)t[n]=e[n];return t.default=e,t}var s=/*#__PURE__*/o(n),i=/*#__PURE__*/o(r);const a=["configExtension","createCommand","createContextState","createImportState","createRenderState","createState","declarePeerDependency","defineExtension","defineImportRule","defineOverlayRules","domOverride","safeCast"],c=new Map([["configExtension",{form:"args"}],["declarePeerDependency",{form:"args"}],["defineExtension",{form:"identity"}],["defineImportRule",{form:"identity"}],["safeCast",{form:"identity"}]]),l=/^[^\S\n]*\*?[^\S\n]*@lexical-inline(?:[^\S\n]+(\S+))?[^\S\n]*$/m;class f extends Error{constructor(e){super(e),this.name="PureAnnotationsError"}}const u=/^[^\S\n]*\*?[^\S\n]*@lexical-pure-namespace[^\S\n]*$/m,p=new Set(["args","identity"]),d=["sel"],m=new Map(Array.from(c,([e,t])=>[e,t.form])),y={contentOnly:!0},h=/[#@]__PURE__/,S=/\.(?:[cm]?[jt]sx?)$/,g=[/^lexical$/,/^@lexical\//],x=/[#@]__NO_SIDE_EFFECTS__/,w=/\bfrom\s*['"]\./,v=new Set(["ArrayExpression","BigIntLiteral","BooleanLiteral","DecimalLiteral","Identifier","JSXElement","JSXFragment","NullLiteral","NumericLiteral","ObjectExpression","RegExpLiteral","StringLiteral","TemplateLiteral","ThisExpression"]),E=[".ts",".tsx",".mts",".cts",".js",".jsx",".mjs",".cjs"],b=new Set(["Array","BigInt","Boolean","Map","Number","Object","RegExp","Set","String","Symbol","WeakMap","WeakSet"]),I=/[\\/]node_modules[\\/]/,C=new Set(["ArrowFunctionExpression","ClassAccessorProperty","ClassMethod","ClassPrivateMethod","ClassPrivateProperty","ClassProperty","FunctionDeclaration","FunctionExpression","ObjectMethod","PropertyDefinition","StaticBlock","TSDeclareMethod"]),_=new Set,M=new Set(["comments","extra","innerComments","leadingComments","loc","trailingComments"]);function j(e,t){const n="string"==typeof e?e:"",r=/\.[cm]?tsx?$/i.test(n),o=["explicitResourceManagement"];return r&&o.push("typescript"),r&&!/\.[cm]?tsx$/i.test(n)||o.push("jsx"),t?o.concat(t):o}function O(e,t){let n=t;for(;n>0&&/\s/.test(e[n-1]);)n--;if(n<4||"/"!==e[n-1]||"*"!==e[n-2])return null;const r=e.lastIndexOf("/*",n-2);return-1===r?null:{end:n,start:r,value:e.slice(r+2,n-2)}}function P(e,t){const n=O(e,t);return null!==n&&h.test(n.value)}function $(e,t,n,r){const{functions:o,namespaces:s}=t,i=r||{discarded:!1,shadowed:_,statementStarts:new Set};if(Array.isArray(e)){for(const r of e)$(r,t,n,{discarded:!1,shadowed:i.shadowed,statementStarts:i.statementStarts});return}if(!e||"object"!=typeof e||"string"!=typeof e.type)return;if(C.has(e.type))return;if("ExpressionStatement"===e.type&&i.statementStarts.add(e.expression.start),"CallExpression"===e.type&&e.callee){const t={discarded:i.discarded,statementStart:i.statementStarts.has(e.start)};if("Identifier"===e.callee.type&&o.has(e.callee.name)&&!i.shadowed.has(e.callee.name))n(e,t);else if(void 0!==s&&s.size>0){const r=function(e){for(let t=e;t;){if("Identifier"===t.type)return t.name;if("MemberExpression"===t.type)t=t.object;else{if("CallExpression"!==t.type)return null;t=t.callee}}return null}(e.callee);null!==r&&s.has(r)&&!i.shadowed.has(r)&&n(e,{...t,namespace:!0})}}const a=function(e){const t="BlockStatement"===e.type?e.body:"SwitchCase"===e.type?e.consequent:null;if(null===t)return null;let n=null;const r=e=>{n=n||new Set,n.add(e)};for(const e of t)if("VariableDeclaration"===e.type&&"var"!==e.kind)for(const t of e.declarations)"Identifier"===t.id.type&&r(t.id.name);else"FunctionDeclaration"!==e.type&&"ClassDeclaration"!==e.type||!e.id||r(e.id.name);return n}(e),c=null===a?i.shadowed:new Set([...i.shadowed,...a]);for(const r of Object.keys(e))if(!M.has(r)){const o=e[r];o&&"object"==typeof o&&$(o,t,n,{discarded:"ExpressionStatement"===e.type&&"expression"===r,shadowed:c,statementStarts:i.statementStarts})}}function A(e,t,n,r){if(Array.isArray(e))for(const o of e)A(o,t,n,r);else if(e&&"object"==typeof e&&"string"==typeof e.type){t(e,n,r);for(const n of Object.keys(e))if(!M.has(n)){const r=e[n];r&&"object"==typeof r&&A(r,t,e,n)}}}function D(e,t,n,r){const o=new Set(r.map(e=>e.callee)),s=new Set(r.map(e=>e.callee.name));if(0!==s.size){A(n,(e,t,n)=>{s.has(e.name)&&!o.has(e)&&function(e,t,n){if("Identifier"!==e.type&&"JSXIdentifier"!==e.type)return!1;if(!t)return!0;switch(t.type){case"ImportDefaultSpecifier":case"ImportNamespaceSpecifier":case"ImportSpecifier":return!1;case"ExportSpecifier":return"local"===n;case"OptionalMemberExpression":case"MemberExpression":return"property"!==n||!0===t.computed;case"ClassMethod":case"ClassProperty":case"ObjectMethod":case"ObjectProperty":return"key"!==n||!0===t.computed;default:return!0}}(e,t,n)&&s.delete(e.name)});for(const r of n.body){if("ImportDeclaration"!==r.type||"type"===r.importKind)continue;const{specifiers:n}=r,o=n.filter(e=>"ImportSpecifier"===e.type),i=o.filter(e=>"type"!==e.importKind&&s.has(e.local.name));if(0===i.length)continue;if(i.length<o.length){const t=new Set(i);for(let n=0;n<o.length;n++){if(!t.has(o[n]))continue;let r=n;for(;r+1<o.length&&t.has(o[r+1]);)r++;r+1<o.length?e.remove(o[n].start,o[r+1].start):e.remove(o[n-1].end,o[r].end),n=r}continue}const a=t.indexOf("}",o[o.length-1].end);if(o.length<n.length){const r=n[n.indexOf(o[0])-1];e.remove(t.indexOf(",",r.end),a+1);continue}e.remove(r.start,r.end)}}}function F(e,t,n,r,o){const s=O(t,n.start);null!==s&&h.test(s.value)&&e.remove(s.start,n.start);const i=n.arguments;if("identity"!==r.form)return e.overwrite(n.start,function(e,t){const n=t.typeArguments||t.typeParameters,r=Math.max(t.callee.end,n?n.end:t.callee.end);return e.indexOf("(",r)+1}(t,n),"([",y),void e.overwrite(n.end-1,n.end,"])",y);!0===o||!v.has(i[0].type)?(e.overwrite(n.start,i[0].start,"(",y),e.overwrite(i[0].end,n.end,")",y)):(e.remove(n.start,i[0].start),e.remove(i[0].end,n.end))}const k=new Map,N=new Map;function R(e,t){if(e)for(const n of e){const e=l.exec(n.value);if(e){const n=e[1]||"";if(!p.has(n)){throw new f(`@lexical/compiler: unknown @lexical-inline form ${n?`"${n}"`:"(none given)"}${t?` in ${t}`:""}. Write \`@lexical-inline <form>\` with one of: ${Array.from(p).sort().join(", ")}.`)}return n}}return null}function T(e){return null!=e&&e.some(e=>x.test(e.value))}function L(e,t){const n=new Map;for(const r of e.body){const e="ExportNamedDeclaration"===r.type&&r.declaration?r.declaration:r,o=(r.leadingComments||[]).concat(e===r?[]:e.leadingComments||[]),s=T(o),i=R(o,t);if("FunctionDeclaration"!==e.type&&"TSDeclareFunction"!==e.type||!e.id){if("VariableDeclaration"===e.type)for(const r of e.declarations){const e=(r.leadingComments||[]).concat(r.init&&r.init.leadingComments||[]);"Identifier"===r.id.type&&(s||T(e))&&n.set(r.id.name,i||R(e,t))}}else s&&n.set(e.id.name,i)}return n}function q(e,t){const n=i.resolve(i.dirname(e),t),r=k.get(n);if(void 0!==r)return r;const o=[],a=i.extname(n);if(""!==a&&(o.push(n),/^\.[cm]?js$/.test(a))){const e=n.slice(0,-a.length);o.push(e+a.replace("js","ts"),e+".tsx")}for(const e of E)o.push(n+e);for(const e of E)o.push(i.join(n,`index${e}`));let c=null;for(const e of o)try{if(s.statSync(e).isFile()){c=e;break}}catch(e){}return k.set(n,c),c}function B(e,t){return z(e,t).functions}function z(t,n){const r=N.get(t);if(void 0!==r)return r;let o=null;try{o=e.parse(s.readFileSync(t,"utf8"),{plugins:j(t,n),sourceType:"module"}).program}catch(e){}const i=null===o?{functions:new Map,namespaces:new Set}:{functions:L(o,t),namespaces:W(o)};return N.set(t,i),i}function U(e,t,n){const r=Y(n.sources,g),o=new Map;function s(e,t,n,r){const s=c.get(t),i=void 0!==s?r||n===s.form?s:void 0:n?{form:n}:void 0;o.set(e,{inline:i,name:t})}for(const[t,r]of L(e,n.filename))s(t,t,r,!1);for(const o of e.body){if("ImportDeclaration"!==o.type)continue;const e=o.source.value,i=G(r,e),a=!i&&!1!==n.relativeImports&&"string"==typeof n.filename&&e.startsWith(".");if(i||a)for(const r of o.specifiers){if("ImportSpecifier"!==r.type||"Identifier"!==r.imported.type)continue;if(i){t.has(r.imported.name)&&s(r.local.name,r.imported.name,null,!0);continue}const o=q(n.filename,e),a=null===o?void 0:B(o,n.parserPlugins).get(r.imported.name);void 0!==a&&s(r.local.name,r.imported.name,a,!1)}}return o}function W(e){const t=new Set,n=e=>(e||[]).some(e=>u.test(e.value));for(const r of e.body){const e="ExportNamedDeclaration"===r.type&&r.declaration?r.declaration:r,o=n(r.leadingComments);if("VariableDeclaration"===e.type)for(const r of e.declarations)"Identifier"===r.id.type&&(o||n(e.leadingComments)||n(r.leadingComments)||r.init&&n(r.init.leadingComments))&&t.add(r.id.name)}return t}function V(e,t){return z(e,t).namespaces}function J(e,t,n){const r=new Set,o=Y(n.sources,g);for(const t of W(e))r.add(t);for(const s of e.body){if("ImportDeclaration"!==s.type)continue;const e=s.source.value,i=G(o,e),a=!i&&!1!==n.relativeImports&&"string"==typeof n.filename&&e.startsWith(".");if(!i&&!a)continue;let c;for(const o of s.specifiers)if("ImportSpecifier"===o.type&&"Identifier"===o.imported.type)if(i)t.has(o.imported.name)&&r.add(o.local.name);else{if(void 0===c){const t=q(n.filename,e);c=null===t?new Set:V(t,n.parserPlugins)}c.has(o.imported.name)&&r.add(o.local.name)}}for(const t of e.body)if("VariableDeclaration"===t.type)for(const e of t.declarations)"Identifier"===e.id.type&&e.init&&"Identifier"===e.init.type&&r.has(e.init.name)&&r.add(e.id.name);return r}function X(e,t){const n=e=>{if(Array.isArray(e))e.forEach(n);else if(e&&"object"==typeof e&&"string"==typeof e.type&&!C.has(e.type)){"CallExpression"!==e.type&&"NewExpression"!==e.type&&"TaggedTemplateExpression"!==e.type||t(e);for(const t of Object.keys(e))M.has(t)||n(e[t])}};e.arguments.forEach(n)}function K(n,r){const o=r||{},s=new Set(o.functions||a),i=new Set(o.namespaces||d);if(!function(e,t,n){if(e.includes("__NO_SIDE_EFFECTS__")||e.includes("@lexical-pure-namespace")||w.test(e))return!0;for(const n of t)if(e.includes(n))return!0;for(const t of n)if(e.includes(t))return!0;return!1}(n,s,i))return null;const c=e.parse(n,{errorRecovery:!1,plugins:j(o.filename,o.parserPlugins),sourceFilename:o.filename,sourceType:"module"}),l=U(c.program,s,o),u=J(c.program,i,o);if(0===l.size&&0===u.size)return null;const p=new Set,m=[],y=[];$(c.program,{functions:l,namespaces:u},(e,t)=>{if(!0===t.namespace)return void(P(n,e.start)||p.add(e.start));y.push(e);const r=l.get(e.callee.name),s=!0===o.inline?r.inline:void 0;void 0!==s&&!t.discarded&&function(e,t){const n=e.arguments;return"identity"!==t.form||1===n.length&&"SpreadElement"!==n[0].type&&"SequenceExpression"!==n[0].type}(e,s)?m.push([e,s,t.statementStart]):P(n,e.start)||p.add(e.start)});const h=Array.from(p);if(!0===o.strict){const e=new Set(p);for(const[t]of m)e.add(t.start);!function(e,t,n,r){const o=[],s=new Set;for(const t of n)X(t,n=>{const i=n.callee||n.tag;if(r.has(n.start)||P(e,n.start)||s.has(n.start)||"Identifier"===i.type&&b.has(i.name))return;s.add(n.start);const a=e.slice(i.start,i.end).replace(/\s+/g," "),c=n.loc?`${n.loc.start.line}:${n.loc.start.column+1}`:"?";o.push(` ${c} ${a}(...) inside ${e.slice(t.callee.start,t.callee.end)}(...)`)});if(o.length>0)throw new f(`@lexical/compiler: ${o.length} call(s) evaluated inside a definition in ${t||"<unknown>"} are not known to be side-effect free, so the definition cannot be tree-shaken:\n${o.join("\n")}\nMake the call lazy, or declare the function side-effect free (@__NO_SIDE_EFFECTS__ plus the transform's \`functions\`/\`namespaces\` options) so that its calls are annotated too.`)}(n,o.filename,y,e)}if(0===h.length&&0===m.length)return null;const S=new t(n);for(const e of h)S.appendLeft(e,"/* @__PURE__ */");for(const[e,t,r]of m)F(S,n,e,t,r);return D(S,n,c.program,m.map(([e])=>e)),{code:S.toString(),count:h.length,inlined:m.length,map:!1===o.sourceMap?void 0:S.generateMap({hires:"boundary",source:o.filename})}}function Y(e,t){return void 0===e?t:Array.isArray(e)?e:[e]}function G(e,t){return e.some(e=>e.test(t))}const H=a,Q=d,Z=m;exports.INLINE_FACTORY_FORMS=Z,exports.PURE_FACTORY_FUNCTIONS=H,exports.PURE_NAMESPACES=Q,exports.pureAnnotations=function(e){return function(e){const t=e||{},n=new Set(t.functions||a),r=Y(t.include,[S]),o=Y(t.exclude,[]);return{enforce:void 0===t.enforce?"post":t.enforce,name:"@lexical/compiler",transform(e,s){const i=function(e){return e.replace(/[?#][\s\S]*$/,"")}(s);if(!G(r,i)||G(o,i))return null;const a=I.test(i);let c=null;try{c=K(e,{filename:i,functions:n,inline:t.inline,namespaces:t.namespaces,parserPlugins:t.parserPlugins,relativeImports:t.relativeImports,sourceMap:t.sourceMap,sources:t.sources,strict:!0===t.strict&&!a})}catch(e){if(e instanceof f&&!a)throw e;return this&&"function"==typeof this.warn&&this.warn(`@lexical/compiler could not parse ${s}, no annotations were added: ${e instanceof Error?e.message:String(e)}`),null}return null===c?null:{code:c.code,map:void 0===c.map?null:c.map}}}}(e)},exports.pureCallNames=function(t,n){return function(t,n){const r=n||{},o=new Set(r.functions||a),s=e.parse(t,{errorRecovery:!1,plugins:j(r.filename,r.parserPlugins),sourceFilename:r.filename,sourceType:"module"});return{functions:new Set(U(s.program,o,r).keys()),namespaces:J(s.program,new Set(r.namespaces||d),r)}}(t,n)},exports.transformPureAnnotations=function(e,t){return K(e,t)};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import{parse as e}from"@babel/parser";import t from"magic-string";import*as n from"node:fs";import*as r from"node:path";const o=["configExtension","createCommand","createContextState","createImportState","createRenderState","createState","declarePeerDependency","defineExtension","defineImportRule","defineOverlayRules","domOverride","safeCast"],s=new Map([["configExtension",{form:"args"}],["declarePeerDependency",{form:"args"}],["defineExtension",{form:"identity"}],["defineImportRule",{form:"identity"}],["safeCast",{form:"identity"}]]),i=/^[^\S\n]*\*?[^\S\n]*@lexical-inline(?:[^\S\n]+(\S+))?[^\S\n]*$/m;class a extends Error{constructor(e){super(e),this.name="PureAnnotationsError"}}const c=/^[^\S\n]*\*?[^\S\n]*@lexical-pure-namespace[^\S\n]*$/m,l=new Set(["args","identity"]),f=["sel"],u=new Map(Array.from(s,([e,t])=>[e,t.form])),p={contentOnly:!0},d=/[#@]__PURE__/,m=/\.(?:[cm]?[jt]sx?)$/,y=[/^lexical$/,/^@lexical\//],h=/[#@]__NO_SIDE_EFFECTS__/,g=/\bfrom\s*['"]\./,S=new Set(["ArrayExpression","BigIntLiteral","BooleanLiteral","DecimalLiteral","Identifier","JSXElement","JSXFragment","NullLiteral","NumericLiteral","ObjectExpression","RegExpLiteral","StringLiteral","TemplateLiteral","ThisExpression"]),w=[".ts",".tsx",".mts",".cts",".js",".jsx",".mjs",".cjs"],x=new Set(["Array","BigInt","Boolean","Map","Number","Object","RegExp","Set","String","Symbol","WeakMap","WeakSet"]),v=/[\\/]node_modules[\\/]/,E=new Set(["ArrowFunctionExpression","ClassAccessorProperty","ClassMethod","ClassPrivateMethod","ClassPrivateProperty","ClassProperty","FunctionDeclaration","FunctionExpression","ObjectMethod","PropertyDefinition","StaticBlock","TSDeclareMethod"]),b=new Set,I=new Set(["comments","extra","innerComments","leadingComments","loc","trailingComments"]);function C(e,t){const n="string"==typeof e?e:"",r=/\.[cm]?tsx?$/i.test(n),o=["explicitResourceManagement"];return r&&o.push("typescript"),r&&!/\.[cm]?tsx$/i.test(n)||o.push("jsx"),t?o.concat(t):o}function _(e,t){let n=t;for(;n>0&&/\s/.test(e[n-1]);)n--;if(n<4||"/"!==e[n-1]||"*"!==e[n-2])return null;const r=e.lastIndexOf("/*",n-2);return-1===r?null:{end:n,start:r,value:e.slice(r+2,n-2)}}function j(e,t){const n=_(e,t);return null!==n&&d.test(n.value)}function M(e,t,n,r){const{functions:o,namespaces:s}=t,i=r||{discarded:!1,shadowed:b,statementStarts:new Set};if(Array.isArray(e)){for(const r of e)M(r,t,n,{discarded:!1,shadowed:i.shadowed,statementStarts:i.statementStarts});return}if(!e||"object"!=typeof e||"string"!=typeof e.type)return;if(E.has(e.type))return;if("ExpressionStatement"===e.type&&i.statementStarts.add(e.expression.start),"CallExpression"===e.type&&e.callee){const t={discarded:i.discarded,statementStart:i.statementStarts.has(e.start)};if("Identifier"===e.callee.type&&o.has(e.callee.name)&&!i.shadowed.has(e.callee.name))n(e,t);else if(void 0!==s&&s.size>0){const r=function(e){for(let t=e;t;){if("Identifier"===t.type)return t.name;if("MemberExpression"===t.type)t=t.object;else{if("CallExpression"!==t.type)return null;t=t.callee}}return null}(e.callee);null!==r&&s.has(r)&&!i.shadowed.has(r)&&n(e,{...t,namespace:!0})}}const a=function(e){const t="BlockStatement"===e.type?e.body:"SwitchCase"===e.type?e.consequent:null;if(null===t)return null;let n=null;const r=e=>{n=n||new Set,n.add(e)};for(const e of t)if("VariableDeclaration"===e.type&&"var"!==e.kind)for(const t of e.declarations)"Identifier"===t.id.type&&r(t.id.name);else"FunctionDeclaration"!==e.type&&"ClassDeclaration"!==e.type||!e.id||r(e.id.name);return n}(e),c=null===a?i.shadowed:new Set([...i.shadowed,...a]);for(const r of Object.keys(e))if(!I.has(r)){const o=e[r];o&&"object"==typeof o&&M(o,t,n,{discarded:"ExpressionStatement"===e.type&&"expression"===r,shadowed:c,statementStarts:i.statementStarts})}}function $(e,t,n,r){if(Array.isArray(e))for(const o of e)$(o,t,n,r);else if(e&&"object"==typeof e&&"string"==typeof e.type){t(e,n,r);for(const n of Object.keys(e))if(!I.has(n)){const r=e[n];r&&"object"==typeof r&&$(r,t,e,n)}}}function D(e,t,n,r){const o=new Set(r.map(e=>e.callee)),s=new Set(r.map(e=>e.callee.name));if(0!==s.size){$(n,(e,t,n)=>{s.has(e.name)&&!o.has(e)&&function(e,t,n){if("Identifier"!==e.type&&"JSXIdentifier"!==e.type)return!1;if(!t)return!0;switch(t.type){case"ImportDefaultSpecifier":case"ImportNamespaceSpecifier":case"ImportSpecifier":return!1;case"ExportSpecifier":return"local"===n;case"OptionalMemberExpression":case"MemberExpression":return"property"!==n||!0===t.computed;case"ClassMethod":case"ClassProperty":case"ObjectMethod":case"ObjectProperty":return"key"!==n||!0===t.computed;default:return!0}}(e,t,n)&&s.delete(e.name)});for(const r of n.body){if("ImportDeclaration"!==r.type||"type"===r.importKind)continue;const{specifiers:n}=r,o=n.filter(e=>"ImportSpecifier"===e.type),i=o.filter(e=>"type"!==e.importKind&&s.has(e.local.name));if(0===i.length)continue;if(i.length<o.length){const t=new Set(i);for(let n=0;n<o.length;n++){if(!t.has(o[n]))continue;let r=n;for(;r+1<o.length&&t.has(o[r+1]);)r++;r+1<o.length?e.remove(o[n].start,o[r+1].start):e.remove(o[n-1].end,o[r].end),n=r}continue}const a=t.indexOf("}",o[o.length-1].end);if(o.length<n.length){const r=n[n.indexOf(o[0])-1];e.remove(t.indexOf(",",r.end),a+1);continue}e.remove(r.start,r.end)}}}function O(e,t,n,r,o){const s=_(t,n.start);null!==s&&d.test(s.value)&&e.remove(s.start,n.start);const i=n.arguments;if("identity"!==r.form)return e.overwrite(n.start,function(e,t){const n=t.typeArguments||t.typeParameters,r=Math.max(t.callee.end,n?n.end:t.callee.end);return e.indexOf("(",r)+1}(t,n),"([",p),void e.overwrite(n.end-1,n.end,"])",p);!0===o||!S.has(i[0].type)?(e.overwrite(n.start,i[0].start,"(",p),e.overwrite(i[0].end,n.end,")",p)):(e.remove(n.start,i[0].start),e.remove(i[0].end,n.end))}const P=new Map,A=new Map;function F(e,t){if(e)for(const n of e){const e=i.exec(n.value);if(e){const n=e[1]||"";if(!l.has(n)){throw new a(`@lexical/compiler: unknown @lexical-inline form ${n?`"${n}"`:"(none given)"}${t?` in ${t}`:""}. Write \`@lexical-inline <form>\` with one of: ${Array.from(l).sort().join(", ")}.`)}return n}}return null}function k(e){return null!=e&&e.some(e=>h.test(e.value))}function T(e,t){const n=new Map;for(const r of e.body){const e="ExportNamedDeclaration"===r.type&&r.declaration?r.declaration:r,o=(r.leadingComments||[]).concat(e===r?[]:e.leadingComments||[]),s=k(o),i=F(o,t);if("FunctionDeclaration"!==e.type&&"TSDeclareFunction"!==e.type||!e.id){if("VariableDeclaration"===e.type)for(const r of e.declarations){const e=(r.leadingComments||[]).concat(r.init&&r.init.leadingComments||[]);"Identifier"===r.id.type&&(s||k(e))&&n.set(r.id.name,i||F(e,t))}}else s&&n.set(e.id.name,i)}return n}function R(e,t){const o=r.resolve(r.dirname(e),t),s=P.get(o);if(void 0!==s)return s;const i=[],a=r.extname(o);if(""!==a&&(i.push(o),/^\.[cm]?js$/.test(a))){const e=o.slice(0,-a.length);i.push(e+a.replace("js","ts"),e+".tsx")}for(const e of w)i.push(o+e);for(const e of w)i.push(r.join(o,`index${e}`));let c=null;for(const e of i)try{if(n.statSync(e).isFile()){c=e;break}}catch(e){}return P.set(o,c),c}function N(e,t){return L(e,t).functions}function L(t,r){const o=A.get(t);if(void 0!==o)return o;let s=null;try{s=e(n.readFileSync(t,"utf8"),{plugins:C(t,r),sourceType:"module"}).program}catch(e){}const i=null===s?{functions:new Map,namespaces:new Set}:{functions:T(s,t),namespaces:z(s)};return A.set(t,i),i}function B(e,t,n){const r=q(n.sources,y),o=new Map;function i(e,t,n,r){const i=s.get(t),a=void 0!==i?r||n===i.form?i:void 0:n?{form:n}:void 0;o.set(e,{inline:a,name:t})}for(const[t,r]of T(e,n.filename))i(t,t,r,!1);for(const o of e.body){if("ImportDeclaration"!==o.type)continue;const e=o.source.value,s=K(r,e),a=!s&&!1!==n.relativeImports&&"string"==typeof n.filename&&e.startsWith(".");if(s||a)for(const r of o.specifiers){if("ImportSpecifier"!==r.type||"Identifier"!==r.imported.type)continue;if(s){t.has(r.imported.name)&&i(r.local.name,r.imported.name,null,!0);continue}const o=R(n.filename,e),a=null===o?void 0:N(o,n.parserPlugins).get(r.imported.name);void 0!==a&&i(r.local.name,r.imported.name,a,!1)}}return o}function z(e){const t=new Set,n=e=>(e||[]).some(e=>c.test(e.value));for(const r of e.body){const e="ExportNamedDeclaration"===r.type&&r.declaration?r.declaration:r,o=n(r.leadingComments);if("VariableDeclaration"===e.type)for(const r of e.declarations)"Identifier"===r.id.type&&(o||n(e.leadingComments)||n(r.leadingComments)||r.init&&n(r.init.leadingComments))&&t.add(r.id.name)}return t}function W(e,t){return L(e,t).namespaces}function V(e,t,n){const r=new Set,o=q(n.sources,y);for(const t of z(e))r.add(t);for(const s of e.body){if("ImportDeclaration"!==s.type)continue;const e=s.source.value,i=K(o,e),a=!i&&!1!==n.relativeImports&&"string"==typeof n.filename&&e.startsWith(".");if(!i&&!a)continue;let c;for(const o of s.specifiers)if("ImportSpecifier"===o.type&&"Identifier"===o.imported.type)if(i)t.has(o.imported.name)&&r.add(o.local.name);else{if(void 0===c){const t=R(n.filename,e);c=null===t?new Set:W(t,n.parserPlugins)}c.has(o.imported.name)&&r.add(o.local.name)}}for(const t of e.body)if("VariableDeclaration"===t.type)for(const e of t.declarations)"Identifier"===e.id.type&&e.init&&"Identifier"===e.init.type&&r.has(e.init.name)&&r.add(e.id.name);return r}function J(e,t){const n=e=>{if(Array.isArray(e))e.forEach(n);else if(e&&"object"==typeof e&&"string"==typeof e.type&&!E.has(e.type)){"CallExpression"!==e.type&&"NewExpression"!==e.type&&"TaggedTemplateExpression"!==e.type||t(e);for(const t of Object.keys(e))I.has(t)||n(e[t])}};e.arguments.forEach(n)}function X(n,r){const s=r||{},i=new Set(s.functions||o),c=new Set(s.namespaces||f);if(!function(e,t,n){if(e.includes("__NO_SIDE_EFFECTS__")||e.includes("@lexical-pure-namespace")||g.test(e))return!0;for(const n of t)if(e.includes(n))return!0;for(const t of n)if(e.includes(t))return!0;return!1}(n,i,c))return null;const l=e(n,{errorRecovery:!1,plugins:C(s.filename,s.parserPlugins),sourceFilename:s.filename,sourceType:"module"}),u=B(l.program,i,s),p=V(l.program,c,s);if(0===u.size&&0===p.size)return null;const d=new Set,m=[],y=[];M(l.program,{functions:u,namespaces:p},(e,t)=>{if(!0===t.namespace)return void(j(n,e.start)||d.add(e.start));y.push(e);const r=u.get(e.callee.name),o=!0===s.inline?r.inline:void 0;void 0!==o&&!t.discarded&&function(e,t){const n=e.arguments;return"identity"!==t.form||1===n.length&&"SpreadElement"!==n[0].type&&"SequenceExpression"!==n[0].type}(e,o)?m.push([e,o,t.statementStart]):j(n,e.start)||d.add(e.start)});const h=Array.from(d);if(!0===s.strict){const e=new Set(d);for(const[t]of m)e.add(t.start);!function(e,t,n,r){const o=[],s=new Set;for(const t of n)J(t,n=>{const i=n.callee||n.tag;if(r.has(n.start)||j(e,n.start)||s.has(n.start)||"Identifier"===i.type&&x.has(i.name))return;s.add(n.start);const a=e.slice(i.start,i.end).replace(/\s+/g," "),c=n.loc?`${n.loc.start.line}:${n.loc.start.column+1}`:"?";o.push(` ${c} ${a}(...) inside ${e.slice(t.callee.start,t.callee.end)}(...)`)});if(o.length>0)throw new a(`@lexical/compiler: ${o.length} call(s) evaluated inside a definition in ${t||"<unknown>"} are not known to be side-effect free, so the definition cannot be tree-shaken:\n${o.join("\n")}\nMake the call lazy, or declare the function side-effect free (@__NO_SIDE_EFFECTS__ plus the transform's \`functions\`/\`namespaces\` options) so that its calls are annotated too.`)}(n,s.filename,y,e)}if(0===h.length&&0===m.length)return null;const S=new t(n);for(const e of h)S.appendLeft(e,"/* @__PURE__ */");for(const[e,t,r]of m)O(S,n,e,t,r);return D(S,n,l.program,m.map(([e])=>e)),{code:S.toString(),count:h.length,inlined:m.length,map:!1===s.sourceMap?void 0:S.generateMap({hires:"boundary",source:s.filename})}}function q(e,t){return void 0===e?t:Array.isArray(e)?e:[e]}function K(e,t){return e.some(e=>e.test(t))}const U=o,G=f,H=u;function Q(e,t){return X(e,t)}function Y(t,n){return function(t,n){const r=n||{},s=new Set(r.functions||o),i=e(t,{errorRecovery:!1,plugins:C(r.filename,r.parserPlugins),sourceFilename:r.filename,sourceType:"module"});return{functions:new Set(B(i.program,s,r).keys()),namespaces:V(i.program,new Set(r.namespaces||f),r)}}(t,n)}function Z(e){return function(e){const t=e||{},n=new Set(t.functions||o),r=q(t.include,[m]),s=q(t.exclude,[]);return{enforce:void 0===t.enforce?"post":t.enforce,name:"@lexical/compiler",transform(e,o){const i=function(e){return e.replace(/[?#][\s\S]*$/,"")}(o);if(!K(r,i)||K(s,i))return null;const c=v.test(i);let l=null;try{l=X(e,{filename:i,functions:n,inline:t.inline,namespaces:t.namespaces,parserPlugins:t.parserPlugins,relativeImports:t.relativeImports,sourceMap:t.sourceMap,sources:t.sources,strict:!0===t.strict&&!c})}catch(e){if(e instanceof a&&!c)throw e;return this&&"function"==typeof this.warn&&this.warn(`@lexical/compiler could not parse ${o}, no annotations were added: ${e instanceof Error?e.message:String(e)}`),null}return null===l?null:{code:l.code,map:void 0===l.map?null:l.map}}}}(e)}export{H as INLINE_FACTORY_FORMS,U as PURE_FACTORY_FUNCTIONS,G as PURE_NAMESPACES,Z as pureAnnotations,Y as pureCallNames,Q as transformPureAnnotations};
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* The subset of a source map that bundlers consume, matching what
|
|
10
|
+
* `magic-string` produces. Declared structurally so this package needs no
|
|
11
|
+
* dependency on any particular bundler's types.
|
|
12
|
+
*/
|
|
13
|
+
export interface PureAnnotationsSourceMap {
|
|
14
|
+
file?: string;
|
|
15
|
+
mappings: string;
|
|
16
|
+
names: string[];
|
|
17
|
+
sources: string[];
|
|
18
|
+
sourcesContent?: (string | null)[];
|
|
19
|
+
version: number;
|
|
20
|
+
}
|
|
21
|
+
export interface TransformPureAnnotationsOptions {
|
|
22
|
+
/**
|
|
23
|
+
* Path of the module being transformed, used to choose the TypeScript and
|
|
24
|
+
* JSX parser plugins (and named as the source map's source).
|
|
25
|
+
*/
|
|
26
|
+
filename?: string;
|
|
27
|
+
/**
|
|
28
|
+
* Names of the factories whose module-scope calls are annotated. Defaults
|
|
29
|
+
* to {@link PURE_FACTORY_FUNCTIONS}.
|
|
30
|
+
*/
|
|
31
|
+
functions?: Iterable<string>;
|
|
32
|
+
/**
|
|
33
|
+
* Replace calls to the factories whose result is a trivial expression over
|
|
34
|
+
* their arguments (`safeCast`, `defineExtension`, `configExtension`,
|
|
35
|
+
* `declarePeerDependency`, `defineImportRule`) with that expression rather
|
|
36
|
+
* than annotating them — a literal needs no annotation to be dropped, and
|
|
37
|
+
* nothing is left to pin the definition it appears in.
|
|
38
|
+
*
|
|
39
|
+
* Off by default, because it assumes the Lexical being built matches this
|
|
40
|
+
* package's version. Lexical's own build turns it on for the bundles it
|
|
41
|
+
* publishes.
|
|
42
|
+
*/
|
|
43
|
+
inline?: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Imported objects whose method calls are side-effect free, so that
|
|
46
|
+
* `sel.tag('p').attr('data-x', true)` is annotated the way a call to a
|
|
47
|
+
* factory function is. Defaults to {@link PURE_NAMESPACES}.
|
|
48
|
+
*/
|
|
49
|
+
namespaces?: Iterable<string>;
|
|
50
|
+
/** Extra `@babel/parser` plugins to parse the module with. */
|
|
51
|
+
parserPlugins?: readonly unknown[];
|
|
52
|
+
/**
|
|
53
|
+
* Set to false to skip reading relatively imported modules to look for a
|
|
54
|
+
* `__NO_SIDE_EFFECTS__` declaration. Defaults to true.
|
|
55
|
+
*/
|
|
56
|
+
relativeImports?: boolean;
|
|
57
|
+
/** Set to false to skip source map generation. */
|
|
58
|
+
sourceMap?: boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Module specifiers whose exports are trusted to be the factories, without
|
|
61
|
+
* reading the module they come from. Defaults to `lexical` and
|
|
62
|
+
* `@lexical/*`; a call to a same-named function from anywhere else is only
|
|
63
|
+
* annotated when the declaration it resolves to is itself marked
|
|
64
|
+
* `__NO_SIDE_EFFECTS__`.
|
|
65
|
+
*/
|
|
66
|
+
sources?: RegExp | readonly RegExp[];
|
|
67
|
+
/**
|
|
68
|
+
* Throw when a call evaluated inside one of the definitions is not known
|
|
69
|
+
* to be side-effect free. Such a call pins the definition into every
|
|
70
|
+
* bundle that imports the module, however well annotated the definition
|
|
71
|
+
* itself is, so this turns a silent loss of tree-shaking into a build
|
|
72
|
+
* error naming the call. Off by default.
|
|
73
|
+
*/
|
|
74
|
+
strict?: boolean;
|
|
75
|
+
}
|
|
76
|
+
export interface PureAnnotationsResult {
|
|
77
|
+
code: string;
|
|
78
|
+
/** The number of annotations that were inserted. */
|
|
79
|
+
count: number;
|
|
80
|
+
/**
|
|
81
|
+
* The number of calls that were replaced by the literal they would have
|
|
82
|
+
* returned. Always 0 unless `inline` is set.
|
|
83
|
+
*/
|
|
84
|
+
inlined: number;
|
|
85
|
+
map?: PureAnnotationsSourceMap;
|
|
86
|
+
}
|
|
87
|
+
export interface PureAnnotationsOptions extends TransformPureAnnotationsOptions {
|
|
88
|
+
/**
|
|
89
|
+
* Vite plugin ordering. Defaults to `'post'` so the transform runs after
|
|
90
|
+
* TypeScript and JSX have been compiled away.
|
|
91
|
+
*/
|
|
92
|
+
enforce?: 'post' | 'pre';
|
|
93
|
+
/** Module ids to skip. Defaults to none. */
|
|
94
|
+
exclude?: RegExp | readonly RegExp[];
|
|
95
|
+
/**
|
|
96
|
+
* Module ids to transform. Defaults to every `.js`/`.jsx`/`.ts`/`.tsx`
|
|
97
|
+
* (and `.mjs`/`.cjs`/`.mts`/`.cts`) module, including those in
|
|
98
|
+
* `node_modules` so that a Lexical package consumed through its `source`
|
|
99
|
+
* export condition is annotated.
|
|
100
|
+
*/
|
|
101
|
+
include?: RegExp | readonly RegExp[];
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* The structural shape of the returned plugin. It is assignable to Vite's
|
|
105
|
+
* `Plugin` and to Rollup's `Plugin`, so it can be dropped into the `plugins`
|
|
106
|
+
* array of either.
|
|
107
|
+
*/
|
|
108
|
+
export interface PureAnnotationsPlugin {
|
|
109
|
+
enforce?: 'post' | 'pre';
|
|
110
|
+
name: string;
|
|
111
|
+
transform(code: string, id: string): {
|
|
112
|
+
code: string;
|
|
113
|
+
map: PureAnnotationsSourceMap | null;
|
|
114
|
+
} | null;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* The Lexical factories that are annotated with `__NO_SIDE_EFFECTS__` at
|
|
118
|
+
* their definition and whose module-scope call sites therefore need a
|
|
119
|
+
* `__PURE__` annotation for bundlers to tree-shake unused definitions.
|
|
120
|
+
*/
|
|
121
|
+
export declare const PURE_FACTORY_FUNCTIONS: readonly string[];
|
|
122
|
+
/**
|
|
123
|
+
* Objects imported from a Lexical package whose method calls are
|
|
124
|
+
* side-effect free, so that a module-scope `sel.tag('p')` is annotated the
|
|
125
|
+
* way a factory call is. Only the outermost call of a chain is annotated:
|
|
126
|
+
* rollup, terser and esbuild all drop the whole chain from that one.
|
|
127
|
+
*/
|
|
128
|
+
export declare const PURE_NAMESPACES: readonly string[];
|
|
129
|
+
/**
|
|
130
|
+
* The factories that `inline` replaces with a literal, and the form each one
|
|
131
|
+
* takes: `identity` returns its single argument and `args` returns all of its
|
|
132
|
+
* arguments as an array. Each is marked `@lexical-inline <form>` where it is
|
|
133
|
+
* defined.
|
|
134
|
+
*/
|
|
135
|
+
export declare const INLINE_FACTORY_FORMS: ReadonlyMap<string, string>;
|
|
136
|
+
/**
|
|
137
|
+
* Insert a `__PURE__` annotation before every module-scope call to one of the
|
|
138
|
+
* side-effect-free Lexical factories that does not already have one. Returns
|
|
139
|
+
* `null` when the module needs no annotations.
|
|
140
|
+
*/
|
|
141
|
+
export declare function transformPureAnnotations(code: string, options?: TransformPureAnnotationsOptions): PureAnnotationsResult | null;
|
|
142
|
+
/**
|
|
143
|
+
* The local names in `code` whose module-scope calls the transform would
|
|
144
|
+
* annotate: `functions` are called directly, `namespaces` are objects whose
|
|
145
|
+
* method calls are annotated. A name qualifies by being imported from a
|
|
146
|
+
* Lexical package, declared in the module as side-effect free, or imported
|
|
147
|
+
* from a relative module that declares it that way. For tooling that needs
|
|
148
|
+
* the same decision without rewriting the module — a lint rule that removes
|
|
149
|
+
* a hand-written annotation only where the build puts one back. Throws on
|
|
150
|
+
* source it cannot parse.
|
|
151
|
+
*/
|
|
152
|
+
export declare function pureCallNames(code: string, options?: TransformPureAnnotationsOptions): {
|
|
153
|
+
functions: ReadonlySet<string>;
|
|
154
|
+
namespaces: ReadonlySet<string>;
|
|
155
|
+
};
|
|
156
|
+
/**
|
|
157
|
+
* A Vite/Rollup plugin that inserts the `__PURE__` annotations that let
|
|
158
|
+
* bundlers tree-shake unused Lexical extension, command, and rule
|
|
159
|
+
* definitions.
|
|
160
|
+
*
|
|
161
|
+
* The published `dist` bundles already carry the annotations, so this is for
|
|
162
|
+
* builds that compile Lexical from its TypeScript source (the `source`
|
|
163
|
+
* export condition, a git checkout, or a vendored copy) — and for annotating
|
|
164
|
+
* the extensions and commands your own application defines.
|
|
165
|
+
*
|
|
166
|
+
* ```js
|
|
167
|
+
* import {pureAnnotations} from '@lexical/compiler';
|
|
168
|
+
*
|
|
169
|
+
* export default defineConfig({plugins: [pureAnnotations()]});
|
|
170
|
+
* ```
|
|
171
|
+
*/
|
|
172
|
+
export declare function pureAnnotations(options?: PureAnnotationsOptions): PureAnnotationsPlugin;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The identifier a member-expression callee is rooted at, so that every call
|
|
3
|
+
* in `sel.tag('p').attr('x')` resolves to `sel`.
|
|
4
|
+
*
|
|
5
|
+
* @param {any} callee
|
|
6
|
+
* @returns {null | string} the name, or null when the callee is not rooted
|
|
7
|
+
* at a plain identifier
|
|
8
|
+
*/
|
|
9
|
+
export function rootObjectName(callee: any): null | string;
|
|
10
|
+
/**
|
|
11
|
+
* The local names in `code` whose module-scope calls this transform would
|
|
12
|
+
* annotate — the same decision {@link transformPureAnnotations} makes, for
|
|
13
|
+
* tooling that needs to ask about a module without rewriting it (Lexical's
|
|
14
|
+
* `no-pure-annotation` ESLint rule removes a hand-written annotation only
|
|
15
|
+
* for a name this returns, so that the build is guaranteed to put it back).
|
|
16
|
+
*
|
|
17
|
+
* `functions` are called directly, `namespaces` are the objects whose method
|
|
18
|
+
* calls (`sel.tag('p').attr('x')`) are annotated.
|
|
19
|
+
*
|
|
20
|
+
* @param {string} code
|
|
21
|
+
* @param {TransformPureAnnotationsOptions} [options]
|
|
22
|
+
* @returns {{functions: Set<string>, namespaces: Set<string>}}
|
|
23
|
+
*/
|
|
24
|
+
export function pureCallNames(code: string, options?: TransformPureAnnotationsOptions): {
|
|
25
|
+
functions: Set<string>;
|
|
26
|
+
namespaces: Set<string>;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Insert a `__PURE__` annotation before every module-scope call to one of the
|
|
30
|
+
* side-effect-free Lexical factories that does not already have one.
|
|
31
|
+
*
|
|
32
|
+
* Returns `null` when the module needs no annotations, so a caller can pass
|
|
33
|
+
* the original source through untouched.
|
|
34
|
+
*
|
|
35
|
+
* @param {string} code
|
|
36
|
+
* @param {TransformPureAnnotationsOptions} [options]
|
|
37
|
+
* @returns {null | PureAnnotationsResult}
|
|
38
|
+
*/
|
|
39
|
+
export function transformPureAnnotations(code: string, options?: TransformPureAnnotationsOptions): null | PureAnnotationsResult;
|
|
40
|
+
/**
|
|
41
|
+
* @typedef {Object} PureAnnotationsOptions
|
|
42
|
+
* @property {'post' | 'pre'} [enforce] Vite plugin ordering, `'post'` by
|
|
43
|
+
* default so the transform runs after TypeScript/JSX has been compiled away.
|
|
44
|
+
* @property {RegExp | ReadonlyArray<RegExp>} [exclude] Module ids to skip.
|
|
45
|
+
* @property {Iterable<string>} [functions] Names of the factories whose
|
|
46
|
+
* module-scope calls are annotated. Defaults to PURE_FACTORY_FUNCTIONS.
|
|
47
|
+
* @property {RegExp | ReadonlyArray<RegExp>} [include] Module ids to
|
|
48
|
+
* transform, defaults to every .js/.jsx/.ts/.tsx (and .mjs/.cjs/.mts/.cts)
|
|
49
|
+
* module.
|
|
50
|
+
* @property {boolean} [inline] Replace calls to the factories whose result
|
|
51
|
+
* is a trivial expression over their arguments with that expression,
|
|
52
|
+
* rather than annotating them. Off by default: it assumes the Lexical
|
|
53
|
+
* being built matches this package's version.
|
|
54
|
+
* @property {ReadonlyArray<any>} [parserPlugins] Extra Babel parser
|
|
55
|
+
* plugins, for syntax the defaults do not cover.
|
|
56
|
+
* @property {boolean} [relativeImports] Set to false to skip reading
|
|
57
|
+
* relatively imported modules to look for a NO_SIDE_EFFECTS declaration.
|
|
58
|
+
* @property {Iterable<string>} [namespaces] Imported objects whose
|
|
59
|
+
* method calls are side-effect free, defaults to PURE_NAMESPACES.
|
|
60
|
+
* @property {boolean} [sourceMap] Set to false to skip source map generation.
|
|
61
|
+
* @property {RegExp | ReadonlyArray<RegExp>} [sources] Module specifiers
|
|
62
|
+
* whose exports are trusted to be the factories, defaults to `lexical` and
|
|
63
|
+
* `@lexical/*`.
|
|
64
|
+
* @property {boolean} [strict] Throw when a call evaluated inside one of the
|
|
65
|
+
* definitions is not known to be side-effect free, since it pins the
|
|
66
|
+
* definition into every bundle that imports the module.
|
|
67
|
+
*/
|
|
68
|
+
/**
|
|
69
|
+
* A Vite/Rollup plugin that inserts the `__PURE__` annotations that let
|
|
70
|
+
* bundlers tree-shake unused Lexical extension, command, and rule
|
|
71
|
+
* definitions. Use it when building Lexical (or your own extensions) from
|
|
72
|
+
* TypeScript source rather than from the published `dist` bundles, which
|
|
73
|
+
* already carry the annotations.
|
|
74
|
+
*
|
|
75
|
+
* @param {PureAnnotationsOptions} [options]
|
|
76
|
+
* @returns {any} the plugin object
|
|
77
|
+
*/
|
|
78
|
+
export function pureAnnotations(options?: PureAnnotationsOptions): any;
|
|
79
|
+
/**
|
|
80
|
+
* The Lexical factories that are annotated with `__NO_SIDE_EFFECTS__` at
|
|
81
|
+
* their definition. That annotation is only honored by esbuild for calls in
|
|
82
|
+
* the same file as the definition (and not at all by webpack/terser), so
|
|
83
|
+
* every module-scope call site needs its own `__PURE__` annotation for
|
|
84
|
+
* bundlers to tree-shake unused extension/command/rule definitions out of
|
|
85
|
+
* application bundles.
|
|
86
|
+
*
|
|
87
|
+
* Argument-position calls (e.g. `configExtension` / `safeCast` inside a
|
|
88
|
+
* `defineExtension` config) matter too: a pure call is only removable when
|
|
89
|
+
* its arguments are also side-effect-free, so one unannotated nested call
|
|
90
|
+
* pins the entire enclosing definition.
|
|
91
|
+
*
|
|
92
|
+
* @type {ReadonlyArray<string>}
|
|
93
|
+
*/
|
|
94
|
+
export const PURE_FACTORY_FUNCTIONS: ReadonlyArray<string>;
|
|
95
|
+
/**
|
|
96
|
+
* An error the author has to act on — a malformed marker, or a call this
|
|
97
|
+
* transform cannot prove is safe — as opposed to source it cannot parse.
|
|
98
|
+
* The plugin passes an unparseable module through with a warning; these it
|
|
99
|
+
* rethrows, because ignoring them would silently produce the bundle the
|
|
100
|
+
* author was trying to avoid.
|
|
101
|
+
*/
|
|
102
|
+
export class PureAnnotationsError extends Error {
|
|
103
|
+
/** @param {string} message */
|
|
104
|
+
constructor(message: string);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Imported objects whose method calls are side-effect free, so that a
|
|
108
|
+
* module-scope call like `sel.tag('p').attr('data-x', true)` is annotated
|
|
109
|
+
* the same way a call to a factory function is. Only the outermost call of
|
|
110
|
+
* a chain is annotated: rollup, terser and esbuild all drop the whole chain
|
|
111
|
+
* from that one annotation.
|
|
112
|
+
*
|
|
113
|
+
* As with the factories, the name is only trusted when it is imported from
|
|
114
|
+
* a Lexical package.
|
|
115
|
+
*/
|
|
116
|
+
export const PURE_NAMESPACES: string[];
|
|
117
|
+
/**
|
|
118
|
+
* The form each inlinable factory is replaced with, for the tests that keep
|
|
119
|
+
* this table honest and for anyone who wants to know what `inline` does.
|
|
120
|
+
*
|
|
121
|
+
* @type {ReadonlyMap<string, string>}
|
|
122
|
+
*/
|
|
123
|
+
export const INLINE_FACTORY_FORMS: ReadonlyMap<string, string>;
|
|
124
|
+
export type TransformPureAnnotationsOptions = {
|
|
125
|
+
/**
|
|
126
|
+
* Path of the module being transformed, used
|
|
127
|
+
* to choose the TypeScript and JSX parser plugins.
|
|
128
|
+
*/
|
|
129
|
+
filename?: string | undefined;
|
|
130
|
+
/**
|
|
131
|
+
* Names of the factories whose
|
|
132
|
+
* module-scope calls are annotated. Defaults to PURE_FACTORY_FUNCTIONS.
|
|
133
|
+
*/
|
|
134
|
+
functions?: Iterable<string> | undefined;
|
|
135
|
+
/**
|
|
136
|
+
* Replace calls to the factories whose result
|
|
137
|
+
* is a trivial expression over their arguments with that expression,
|
|
138
|
+
* rather than annotating them. Off by default: it assumes the Lexical
|
|
139
|
+
* being built matches this package's version.
|
|
140
|
+
*/
|
|
141
|
+
inline?: boolean | undefined;
|
|
142
|
+
/**
|
|
143
|
+
* Extra Babel parser
|
|
144
|
+
* plugins, for syntax the defaults do not cover.
|
|
145
|
+
*/
|
|
146
|
+
parserPlugins?: readonly any[] | undefined;
|
|
147
|
+
/**
|
|
148
|
+
* Set to false to skip reading
|
|
149
|
+
* relatively imported modules to look for a NO_SIDE_EFFECTS declaration.
|
|
150
|
+
*/
|
|
151
|
+
relativeImports?: boolean | undefined;
|
|
152
|
+
/**
|
|
153
|
+
* Imported objects whose
|
|
154
|
+
* method calls are side-effect free, defaults to PURE_NAMESPACES.
|
|
155
|
+
*/
|
|
156
|
+
namespaces?: Iterable<string> | undefined;
|
|
157
|
+
/**
|
|
158
|
+
* Set to false to skip source map generation.
|
|
159
|
+
*/
|
|
160
|
+
sourceMap?: boolean | undefined;
|
|
161
|
+
/**
|
|
162
|
+
* Module specifiers
|
|
163
|
+
* whose exports are trusted to be the factories, defaults to `lexical` and
|
|
164
|
+
* `@lexical/*`.
|
|
165
|
+
*/
|
|
166
|
+
sources?: RegExp | readonly RegExp[] | undefined;
|
|
167
|
+
/**
|
|
168
|
+
* Throw when a call evaluated inside one of the
|
|
169
|
+
* definitions is not known to be side-effect free, since it pins the
|
|
170
|
+
* definition into every bundle that imports the module.
|
|
171
|
+
*/
|
|
172
|
+
strict?: boolean | undefined;
|
|
173
|
+
};
|
|
174
|
+
export type PureAnnotationsResult = {
|
|
175
|
+
/**
|
|
176
|
+
* Number of annotations that were inserted.
|
|
177
|
+
*/
|
|
178
|
+
count: number;
|
|
179
|
+
code: string;
|
|
180
|
+
/**
|
|
181
|
+
* Number of calls that were replaced by the
|
|
182
|
+
* literal they would have returned.
|
|
183
|
+
*/
|
|
184
|
+
inlined: number;
|
|
185
|
+
map?: any;
|
|
186
|
+
};
|
|
187
|
+
export type PureAnnotationsOptions = {
|
|
188
|
+
/**
|
|
189
|
+
* Vite plugin ordering, `'post'` by
|
|
190
|
+
* default so the transform runs after TypeScript/JSX has been compiled away.
|
|
191
|
+
*/
|
|
192
|
+
enforce?: "pre" | "post" | undefined;
|
|
193
|
+
/**
|
|
194
|
+
* Module ids to skip.
|
|
195
|
+
*/
|
|
196
|
+
exclude?: RegExp | readonly RegExp[] | undefined;
|
|
197
|
+
/**
|
|
198
|
+
* Names of the factories whose
|
|
199
|
+
* module-scope calls are annotated. Defaults to PURE_FACTORY_FUNCTIONS.
|
|
200
|
+
*/
|
|
201
|
+
functions?: Iterable<string> | undefined;
|
|
202
|
+
/**
|
|
203
|
+
* Module ids to
|
|
204
|
+
* transform, defaults to every .js/.jsx/.ts/.tsx (and .mjs/.cjs/.mts/.cts)
|
|
205
|
+
* module.
|
|
206
|
+
*/
|
|
207
|
+
include?: RegExp | readonly RegExp[] | undefined;
|
|
208
|
+
/**
|
|
209
|
+
* Replace calls to the factories whose result
|
|
210
|
+
* is a trivial expression over their arguments with that expression,
|
|
211
|
+
* rather than annotating them. Off by default: it assumes the Lexical
|
|
212
|
+
* being built matches this package's version.
|
|
213
|
+
*/
|
|
214
|
+
inline?: boolean | undefined;
|
|
215
|
+
/**
|
|
216
|
+
* Extra Babel parser
|
|
217
|
+
* plugins, for syntax the defaults do not cover.
|
|
218
|
+
*/
|
|
219
|
+
parserPlugins?: readonly any[] | undefined;
|
|
220
|
+
/**
|
|
221
|
+
* Set to false to skip reading
|
|
222
|
+
* relatively imported modules to look for a NO_SIDE_EFFECTS declaration.
|
|
223
|
+
*/
|
|
224
|
+
relativeImports?: boolean | undefined;
|
|
225
|
+
/**
|
|
226
|
+
* Imported objects whose
|
|
227
|
+
* method calls are side-effect free, defaults to PURE_NAMESPACES.
|
|
228
|
+
*/
|
|
229
|
+
namespaces?: Iterable<string> | undefined;
|
|
230
|
+
/**
|
|
231
|
+
* Set to false to skip source map generation.
|
|
232
|
+
*/
|
|
233
|
+
sourceMap?: boolean | undefined;
|
|
234
|
+
/**
|
|
235
|
+
* Module specifiers
|
|
236
|
+
* whose exports are trusted to be the factories, defaults to `lexical` and
|
|
237
|
+
* `@lexical/*`.
|
|
238
|
+
*/
|
|
239
|
+
sources?: RegExp | readonly RegExp[] | undefined;
|
|
240
|
+
/**
|
|
241
|
+
* Throw when a call evaluated inside one of the
|
|
242
|
+
* definitions is not known to be side-effect free, since it pins the
|
|
243
|
+
* definition into every bundle that imports the module.
|
|
244
|
+
*/
|
|
245
|
+
strict?: boolean | undefined;
|
|
246
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// You are seeing this declaration file because your TypeScript cannot read
|
|
10
|
+
// Lexical's types through the package.json "exports" field.
|
|
11
|
+
//
|
|
12
|
+
// Lexical requires TypeScript >= 5.2 with "moduleResolution" set to
|
|
13
|
+
// "bundler", "node16", or "nodenext". To fix this:
|
|
14
|
+
// 1. Upgrade TypeScript to >= 5.2.
|
|
15
|
+
// 2. In tsconfig.json set "moduleResolution" to "bundler" (recommended for
|
|
16
|
+
// apps/bundlers) or "node16" / "nodenext", and a matching "module".
|
|
17
|
+
import 'Lexical requires TypeScript >=5.2 with moduleResolution bundler, node16, or nodenext';
|
|
18
|
+
export {};
|