@fluixi/compiler 1.0.0-alpha.100
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/LICENSE +21 -0
- package/README.md +131 -0
- package/dist/analyze/expr-shape.cjs +62 -0
- package/dist/analyze/expr-shape.d.cts +14 -0
- package/dist/analyze/expr-shape.d.ts +15 -0
- package/dist/analyze/expr-shape.d.ts.map +1 -0
- package/dist/analyze/expr-shape.js +37 -0
- package/dist/analyze/expr-shape.mjs +41 -0
- package/dist/analyze/intrinsics.cjs +112 -0
- package/dist/analyze/intrinsics.d.cts +80 -0
- package/dist/analyze/intrinsics.d.ts +81 -0
- package/dist/analyze/intrinsics.d.ts.map +1 -0
- package/dist/analyze/intrinsics.js +126 -0
- package/dist/analyze/intrinsics.mjs +91 -0
- package/dist/analyze/paren.cjs +134 -0
- package/dist/analyze/paren.d.cts +23 -0
- package/dist/analyze/paren.d.ts +24 -0
- package/dist/analyze/paren.d.ts.map +1 -0
- package/dist/analyze/paren.js +168 -0
- package/dist/analyze/paren.mjs +113 -0
- package/dist/analyze/props-destructure.cjs +226 -0
- package/dist/analyze/props-destructure.d.cts +83 -0
- package/dist/analyze/props-destructure.d.ts +84 -0
- package/dist/analyze/props-destructure.d.ts.map +1 -0
- package/dist/analyze/props-destructure.js +272 -0
- package/dist/analyze/props-destructure.mjs +205 -0
- package/dist/analyze/reactive-bindings.cjs +210 -0
- package/dist/analyze/reactive-bindings.d.cts +42 -0
- package/dist/analyze/reactive-bindings.d.ts +43 -0
- package/dist/analyze/reactive-bindings.d.ts.map +1 -0
- package/dist/analyze/reactive-bindings.js +191 -0
- package/dist/analyze/reactive-bindings.mjs +187 -0
- package/dist/analyze/reactive-expr.cjs +38 -0
- package/dist/analyze/reactive-expr.d.cts +38 -0
- package/dist/analyze/reactive-expr.d.ts +39 -0
- package/dist/analyze/reactive-expr.d.ts.map +1 -0
- package/dist/analyze/reactive-expr.js +31 -0
- package/dist/analyze/reactive-expr.mjs +17 -0
- package/dist/analyze/static-graph.cjs +831 -0
- package/dist/analyze/static-graph.d.cts +102 -0
- package/dist/analyze/static-graph.d.ts +103 -0
- package/dist/analyze/static-graph.d.ts.map +1 -0
- package/dist/analyze/static-graph.js +871 -0
- package/dist/analyze/static-graph.mjs +813 -0
- package/dist/babel-I6BUWUCU.mjs +636 -0
- package/dist/chunk-3AICWNF7.mjs +92 -0
- package/dist/chunk-6CWJWGE2.mjs +2170 -0
- package/dist/chunk-C3XPDB4Y.mjs +16 -0
- package/dist/chunk-GX5XV6Z7.mjs +190 -0
- package/dist/chunk-HXEXPWJ2.mjs +999 -0
- package/dist/chunk-NU3W67UZ.mjs +584 -0
- package/dist/chunk-SKAVY75W.mjs +11 -0
- package/dist/codegen/backend.cjs +18 -0
- package/dist/codegen/backend.d.cts +35 -0
- package/dist/codegen/backend.d.ts +36 -0
- package/dist/codegen/backend.d.ts.map +1 -0
- package/dist/codegen/backend.js +1 -0
- package/dist/codegen/backend.mjs +0 -0
- package/dist/codegen/backends/imperative.cjs +577 -0
- package/dist/codegen/backends/imperative.d.cts +11 -0
- package/dist/codegen/backends/imperative.d.ts +12 -0
- package/dist/codegen/backends/imperative.d.ts.map +1 -0
- package/dist/codegen/backends/imperative.js +362 -0
- package/dist/codegen/backends/imperative.mjs +554 -0
- package/dist/codegen/contract.cjs +52 -0
- package/dist/codegen/contract.d.cts +24 -0
- package/dist/codegen/contract.d.ts +25 -0
- package/dist/codegen/contract.d.ts.map +1 -0
- package/dist/codegen/contract.js +30 -0
- package/dist/codegen/contract.mjs +31 -0
- package/dist/codegen/partial-template.cjs +176 -0
- package/dist/codegen/partial-template.d.cts +61 -0
- package/dist/codegen/partial-template.d.ts +62 -0
- package/dist/codegen/partial-template.d.ts.map +1 -0
- package/dist/codegen/partial-template.js +0 -0
- package/dist/codegen/partial-template.mjs +153 -0
- package/dist/codegen/serialize-static.cjs +125 -0
- package/dist/codegen/serialize-static.d.cts +38 -0
- package/dist/codegen/serialize-static.d.ts +39 -0
- package/dist/codegen/serialize-static.d.ts.map +1 -0
- package/dist/codegen/serialize-static.js +165 -0
- package/dist/codegen/serialize-static.mjs +104 -0
- package/dist/frontend/babel/build-ir-lit.cjs +1933 -0
- package/dist/frontend/babel/build-ir-lit.d.cts +26 -0
- package/dist/frontend/babel/build-ir-lit.d.ts +27 -0
- package/dist/frontend/babel/build-ir-lit.d.ts.map +1 -0
- package/dist/frontend/babel/build-ir-lit.js +13 -0
- package/dist/frontend/babel/build-ir-lit.mjs +1902 -0
- package/dist/frontend/babel/build-ir.cjs +1948 -0
- package/dist/frontend/babel/build-ir.d.cts +35 -0
- package/dist/frontend/babel/build-ir.d.ts +36 -0
- package/dist/frontend/babel/build-ir.d.ts.map +1 -0
- package/dist/frontend/babel/build-ir.js +124 -0
- package/dist/frontend/babel/build-ir.mjs +1919 -0
- package/dist/frontend/babel/index.cjs +2610 -0
- package/dist/frontend/babel/index.d.cts +33 -0
- package/dist/frontend/babel/index.d.ts +34 -0
- package/dist/frontend/babel/index.d.ts.map +1 -0
- package/dist/frontend/babel/index.js +65 -0
- package/dist/frontend/babel/index.mjs +2580 -0
- package/dist/frontend/babel/lower-template.cjs +1931 -0
- package/dist/frontend/babel/lower-template.d.cts +23 -0
- package/dist/frontend/babel/lower-template.d.ts +24 -0
- package/dist/frontend/babel/lower-template.d.ts.map +1 -0
- package/dist/frontend/babel/lower-template.js +64 -0
- package/dist/frontend/babel/lower-template.mjs +1902 -0
- package/dist/frontend/babel/plugin.cjs +2556 -0
- package/dist/frontend/babel/plugin.d.cts +95 -0
- package/dist/frontend/babel/plugin.d.ts +96 -0
- package/dist/frontend/babel/plugin.d.ts.map +1 -0
- package/dist/frontend/babel/plugin.js +523 -0
- package/dist/frontend/babel/plugin.mjs +2527 -0
- package/dist/frontend/babel/server-functions.cjs +110 -0
- package/dist/frontend/babel/server-functions.d.cts +10 -0
- package/dist/frontend/babel/server-functions.d.ts +11 -0
- package/dist/frontend/babel/server-functions.d.ts.map +1 -0
- package/dist/frontend/babel/server-functions.js +81 -0
- package/dist/frontend/babel/server-functions.mjs +89 -0
- package/dist/frontend/babel/types.cjs +18 -0
- package/dist/frontend/babel/types.d.cts +33 -0
- package/dist/frontend/babel/types.d.ts +34 -0
- package/dist/frontend/babel/types.d.ts.map +1 -0
- package/dist/frontend/babel/types.js +1 -0
- package/dist/frontend/babel/types.mjs +0 -0
- package/dist/frontend/types.cjs +18 -0
- package/dist/frontend/types.d.cts +25 -0
- package/dist/frontend/types.d.ts +26 -0
- package/dist/frontend/types.d.ts.map +1 -0
- package/dist/frontend/types.js +1 -0
- package/dist/frontend/types.mjs +0 -0
- package/dist/frontend/vocabulary.cjs +98 -0
- package/dist/frontend/vocabulary.d.cts +79 -0
- package/dist/frontend/vocabulary.d.ts +80 -0
- package/dist/frontend/vocabulary.d.ts.map +1 -0
- package/dist/frontend/vocabulary.js +124 -0
- package/dist/frontend/vocabulary.mjs +77 -0
- package/dist/index.cjs +1957 -0
- package/dist/index.d.cts +27 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +38 -0
- package/dist/index.mjs +1949 -0
- package/dist/integrations.cjs +5705 -0
- package/dist/integrations.d.cts +215 -0
- package/dist/integrations.d.ts +216 -0
- package/dist/integrations.d.ts.map +1 -0
- package/dist/integrations.js +566 -0
- package/dist/integrations.mjs +810 -0
- package/dist/ir/nodes.cjs +18 -0
- package/dist/ir/nodes.d.cts +168 -0
- package/dist/ir/nodes.d.ts +169 -0
- package/dist/ir/nodes.d.ts.map +1 -0
- package/dist/ir/nodes.js +1 -0
- package/dist/ir/nodes.mjs +0 -0
- package/dist/lower/compile-template.cjs +1670 -0
- package/dist/lower/compile-template.d.cts +82 -0
- package/dist/lower/compile-template.d.ts +83 -0
- package/dist/lower/compile-template.d.ts.map +1 -0
- package/dist/lower/compile-template.js +79 -0
- package/dist/lower/compile-template.mjs +1662 -0
- package/dist/lower/entities.cjs +288 -0
- package/dist/lower/entities.d.cts +1 -0
- package/dist/lower/entities.d.ts +2 -0
- package/dist/lower/entities.d.ts.map +1 -0
- package/dist/lower/entities.js +54 -0
- package/dist/lower/entities.mjs +267 -0
- package/dist/lower/jsx.cjs +1101 -0
- package/dist/lower/jsx.d.cts +33 -0
- package/dist/lower/jsx.d.ts +34 -0
- package/dist/lower/jsx.d.ts.map +1 -0
- package/dist/lower/jsx.js +414 -0
- package/dist/lower/jsx.mjs +1078 -0
- package/dist/lower/template.cjs +1354 -0
- package/dist/lower/template.d.cts +53 -0
- package/dist/lower/template.d.ts +54 -0
- package/dist/lower/template.d.ts.map +1 -0
- package/dist/lower/template.js +542 -0
- package/dist/lower/template.mjs +1335 -0
- package/dist/lower/text.cjs +42 -0
- package/dist/lower/text.d.cts +10 -0
- package/dist/lower/text.d.ts +11 -0
- package/dist/lower/text.d.ts.map +1 -0
- package/dist/lower/text.js +31 -0
- package/dist/lower/text.mjs +21 -0
- package/dist/optimize/analyze-static.cjs +112 -0
- package/dist/optimize/analyze-static.d.cts +39 -0
- package/dist/optimize/analyze-static.d.ts +40 -0
- package/dist/optimize/analyze-static.d.ts.map +1 -0
- package/dist/optimize/analyze-static.js +131 -0
- package/dist/optimize/analyze-static.mjs +91 -0
- package/dist/optimize/collapse-strategies.cjs +90 -0
- package/dist/optimize/collapse-strategies.d.cts +30 -0
- package/dist/optimize/collapse-strategies.d.ts +31 -0
- package/dist/optimize/collapse-strategies.d.ts.map +1 -0
- package/dist/optimize/collapse-strategies.js +33 -0
- package/dist/optimize/collapse-strategies.mjs +67 -0
- package/dist/options.cjs +33 -0
- package/dist/options.d.cts +39 -0
- package/dist/options.d.ts +40 -0
- package/dist/options.d.ts.map +1 -0
- package/dist/options.js +8 -0
- package/dist/options.mjs +12 -0
- package/dist/resolve/builtins.cjs +73 -0
- package/dist/resolve/builtins.d.cts +68 -0
- package/dist/resolve/builtins.d.ts +69 -0
- package/dist/resolve/builtins.d.ts.map +1 -0
- package/dist/resolve/builtins.js +64 -0
- package/dist/resolve/builtins.mjs +53 -0
- package/dist/resolve/component-globals.cjs +272 -0
- package/dist/resolve/component-globals.d.cts +88 -0
- package/dist/resolve/component-globals.d.ts +89 -0
- package/dist/resolve/component-globals.d.ts.map +1 -0
- package/dist/resolve/component-globals.js +160 -0
- package/dist/resolve/component-globals.mjs +249 -0
- package/dist/resolve/component-resolver.cjs +80 -0
- package/dist/resolve/component-resolver.d.cts +68 -0
- package/dist/resolve/component-resolver.d.ts +69 -0
- package/dist/resolve/component-resolver.d.ts.map +1 -0
- package/dist/resolve/component-resolver.js +95 -0
- package/dist/resolve/component-resolver.mjs +59 -0
- package/dist/resolve/load-directive.cjs +93 -0
- package/dist/resolve/load-directive.d.cts +53 -0
- package/dist/resolve/load-directive.d.ts +54 -0
- package/dist/resolve/load-directive.d.ts.map +1 -0
- package/dist/resolve/load-directive.js +93 -0
- package/dist/resolve/load-directive.mjs +72 -0
- package/dist/resolve/resolve-ir.cjs +108 -0
- package/dist/resolve/resolve-ir.d.cts +53 -0
- package/dist/resolve/resolve-ir.d.ts +54 -0
- package/dist/resolve/resolve-ir.d.ts.map +1 -0
- package/dist/resolve/resolve-ir.js +58 -0
- package/dist/resolve/resolve-ir.mjs +85 -0
- package/dist/resolve/write-globals.cjs +383 -0
- package/dist/resolve/write-globals.d.cts +36 -0
- package/dist/resolve/write-globals.d.ts +37 -0
- package/dist/resolve/write-globals.d.ts.map +1 -0
- package/dist/resolve/write-globals.js +169 -0
- package/dist/resolve/write-globals.mjs +362 -0
- package/dist/server-fns-VZLHMQTC.mjs +79 -0
- package/dist/server-functions-UAZKOLZW.mjs +82 -0
- package/dist/transform/bindings.cjs +71 -0
- package/dist/transform/bindings.d.cts +16 -0
- package/dist/transform/bindings.d.ts +17 -0
- package/dist/transform/bindings.d.ts.map +1 -0
- package/dist/transform/bindings.js +69 -0
- package/dist/transform/bindings.mjs +50 -0
- package/dist/transform/index.cjs +3837 -0
- package/dist/transform/index.d.cts +15 -0
- package/dist/transform/index.d.ts +16 -0
- package/dist/transform/index.d.ts.map +1 -0
- package/dist/transform/index.js +12 -0
- package/dist/transform/index.mjs +4882 -0
- package/dist/transform/intrinsics.cjs +261 -0
- package/dist/transform/intrinsics.d.cts +33 -0
- package/dist/transform/intrinsics.d.ts +34 -0
- package/dist/transform/intrinsics.d.ts.map +1 -0
- package/dist/transform/intrinsics.js +120 -0
- package/dist/transform/intrinsics.mjs +238 -0
- package/dist/transform/props.cjs +441 -0
- package/dist/transform/props.d.cts +45 -0
- package/dist/transform/props.d.ts +46 -0
- package/dist/transform/props.d.ts.map +1 -0
- package/dist/transform/props.js +221 -0
- package/dist/transform/props.mjs +1487 -0
- package/dist/transform/server-fn-id.cjs +35 -0
- package/dist/transform/server-fn-id.d.cts +9 -0
- package/dist/transform/server-fn-id.d.ts +10 -0
- package/dist/transform/server-fn-id.d.ts.map +1 -0
- package/dist/transform/server-fn-id.js +18 -0
- package/dist/transform/server-fn-id.mjs +14 -0
- package/dist/transform/server-fns.cjs +114 -0
- package/dist/transform/server-fns.d.cts +12 -0
- package/dist/transform/server-fns.d.ts +13 -0
- package/dist/transform/server-fns.d.ts.map +1 -0
- package/dist/transform/server-fns.js +94 -0
- package/dist/transform/server-fns.mjs +1160 -0
- package/dist/transform/source-locations.cjs +393 -0
- package/dist/transform/source-locations.d.cts +48 -0
- package/dist/transform/source-locations.d.ts +49 -0
- package/dist/transform/source-locations.d.ts.map +1 -0
- package/dist/transform/source-locations.js +303 -0
- package/dist/transform/source-locations.mjs +370 -0
- package/dist/transform/styles.cjs +606 -0
- package/dist/transform/styles.d.cts +237 -0
- package/dist/transform/styles.d.ts +238 -0
- package/dist/transform/styles.d.ts.map +1 -0
- package/dist/transform/styles.js +743 -0
- package/dist/transform/styles.mjs +671 -0
- package/dist/transform/templates.cjs +3806 -0
- package/dist/transform/templates.d.cts +82 -0
- package/dist/transform/templates.d.ts +83 -0
- package/dist/transform/templates.d.ts.map +1 -0
- package/dist/transform/templates.js +613 -0
- package/dist/transform/templates.mjs +4852 -0
- package/dist/transform-3W45L3EA.mjs +951 -0
- package/dist/tsconfig.lib.tsbuildinfo +1 -0
- package/dist/vite-styles.cjs +223 -0
- package/dist/vite-styles.d.cts +68 -0
- package/dist/vite-styles.d.ts +69 -0
- package/dist/vite-styles.d.ts.map +1 -0
- package/dist/vite-styles.js +241 -0
- package/dist/vite-styles.mjs +214 -0
- package/package.json +141 -0
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The reactive primitives the compiler knows by name, in one place.
|
|
3
|
+
*
|
|
4
|
+
* Two ways to write the same thing. The runtime call, which needs an import and works
|
|
5
|
+
* without us:
|
|
6
|
+
*
|
|
7
|
+
* import { createSignal } from '@fluixi/reactive/signal';
|
|
8
|
+
* const count = createSignal(0);
|
|
9
|
+
*
|
|
10
|
+
* And the intrinsic, which the compiler resolves and imports for you:
|
|
11
|
+
*
|
|
12
|
+
* const count = $signal(0);
|
|
13
|
+
*
|
|
14
|
+
* They are not two reactive systems. `$signal` compiles to the same `createSignal` call,
|
|
15
|
+
* so there's one graph, one lifecycle, one SSR story. The `$` form is authoring sugar
|
|
16
|
+
* the compiler understands; the runtime form stays public, because a library that never
|
|
17
|
+
* runs this compiler still has to be able to write reactive code.
|
|
18
|
+
*
|
|
19
|
+
* Everything the compiler needs to know about a primitive lives in this table rather
|
|
20
|
+
* than spread across passes, so adding one is an entry, not a new code path.
|
|
21
|
+
*/
|
|
22
|
+
/** Module the reactive primitives are imported from when the compiler adds the import. */
|
|
23
|
+
export const REACTIVE_MODULE = '@fluixi/reactive/signal';
|
|
24
|
+
/**
|
|
25
|
+
* `$name` → the runtime it stands for.
|
|
26
|
+
*
|
|
27
|
+
* The `$` prefix is reserved. A local binding of the same name wins, it has to, or the
|
|
28
|
+
* compiler would rewrite code that means something else, and that's reported rather
|
|
29
|
+
* than done quietly.
|
|
30
|
+
*/
|
|
31
|
+
export const INTRINSICS = {
|
|
32
|
+
$signal: { export: 'signal', module: REACTIVE_MODULE, returns: 'signal-handle' },
|
|
33
|
+
$memo: { export: 'memo', module: REACTIVE_MODULE, returns: 'memo-handle' },
|
|
34
|
+
$effect: { export: 'effect', module: REACTIVE_MODULE, returns: 'effect' },
|
|
35
|
+
$store: { export: 'store', module: '@fluixi/reactive/store', returns: 'store-handle' },
|
|
36
|
+
$resource: { export: 'resource', module: REACTIVE_MODULE, returns: 'resource-handle' },
|
|
37
|
+
$cachedResource: { export: 'cachedResource', module: '@fluixi/reactive/cached-resource', returns: 'resource-handle' },
|
|
38
|
+
// No short runtime form for these yet, so the intrinsic stands for the `create*`
|
|
39
|
+
// name. Still worth having: no import to write, and when a shorter form is
|
|
40
|
+
// designed, the change is this line rather than a compiler pass.
|
|
41
|
+
$selector: { export: 'createSelector', module: REACTIVE_MODULE, returns: 'memo-accessor' },
|
|
42
|
+
$deferred: { export: 'createDeferred', module: REACTIVE_MODULE, returns: 'memo-accessor' },
|
|
43
|
+
// Not value constructors, but the compiler has to know them: they change what a read
|
|
44
|
+
// does. `untrack` suppresses dependency collection, which is exactly the kind of thing
|
|
45
|
+
// dependency analysis must not guess at.
|
|
46
|
+
$untrack: { export: 'untrack', module: REACTIVE_MODULE, returns: 'plain' },
|
|
47
|
+
$untrackStore: { export: 'untrackStore', module: '@fluixi/reactive/store', returns: 'plain' },
|
|
48
|
+
// Scopes, scheduling and lifecycle: no value to classify, but the same authoring promise,
|
|
49
|
+
// no import to write. `$cleanup` registers a callback on the current owner (`onCleanup`).
|
|
50
|
+
$batch: { export: 'batch', module: REACTIVE_MODULE, returns: 'plain' },
|
|
51
|
+
$cleanup: { export: 'onCleanup', module: REACTIVE_MODULE, returns: 'plain' },
|
|
52
|
+
$root: { export: 'root', module: REACTIVE_MODULE, returns: 'plain' },
|
|
53
|
+
$context: { export: 'context', module: REACTIVE_MODULE, returns: 'plain' },
|
|
54
|
+
$renderEffect: { export: 'renderEffect', module: REACTIVE_MODULE, returns: 'effect' },
|
|
55
|
+
$computed: { export: 'computed', module: REACTIVE_MODULE, returns: 'effect' },
|
|
56
|
+
// Storage for where the code runs, and a signal kept in it. `$persisted` is a signal
|
|
57
|
+
// handle as far as reads go: the same accessor with `set` on it.
|
|
58
|
+
$storage: { export: 'useStorage', module: '@fluixi/core/storage', returns: 'plain' },
|
|
59
|
+
$asyncStorage: { export: 'useAsyncStorage', module: '@fluixi/core/storage', returns: 'plain' },
|
|
60
|
+
$persisted: { export: 'persisted', module: '@fluixi/core/storage', returns: 'signal-handle' },
|
|
61
|
+
// An environment variable, public or server-only; the browser build refuses a secret.
|
|
62
|
+
$env: { export: 'env', module: '@fluixi/start/env', returns: 'plain' },
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* The runtime names, for the other direction: source that imports `createSignal` gets
|
|
66
|
+
* classified the same way as source that writes `$signal`, so later passes see one
|
|
67
|
+
* vocabulary whichever form the author used.
|
|
68
|
+
*/
|
|
69
|
+
export const RUNTIME_PRIMITIVES = {
|
|
70
|
+
signal: 'signal-handle',
|
|
71
|
+
memo: 'memo-handle',
|
|
72
|
+
effect: 'effect',
|
|
73
|
+
store: 'store-handle',
|
|
74
|
+
createSignal: ['signal-accessor', 'signal-setter'],
|
|
75
|
+
createMemo: 'memo-accessor',
|
|
76
|
+
createEffect: 'effect',
|
|
77
|
+
createRenderEffect: 'effect',
|
|
78
|
+
renderEffect: 'effect',
|
|
79
|
+
computed: 'effect',
|
|
80
|
+
createStore: 'reactive-object',
|
|
81
|
+
resource: 'resource-handle',
|
|
82
|
+
cachedResource: 'resource-handle',
|
|
83
|
+
createResource: 'reactive-object',
|
|
84
|
+
createSelector: 'memo-accessor',
|
|
85
|
+
createDeferred: 'memo-accessor',
|
|
86
|
+
};
|
|
87
|
+
/** Modules whose exports count as reactive primitives. */
|
|
88
|
+
export const PRIMITIVE_MODULES = [
|
|
89
|
+
'@fluixi/reactive',
|
|
90
|
+
'@fluixi/reactive/signal',
|
|
91
|
+
'@fluixi/reactive/store',
|
|
92
|
+
'@fluixi/reactive/cached-resource',
|
|
93
|
+
'@fluixi/core',
|
|
94
|
+
];
|
|
95
|
+
/**
|
|
96
|
+
* Cheap text check for the file-skipping fast path: a module with no `$` call never
|
|
97
|
+
* needs parsing. Non-global, so it has no lastIndex to carry between calls.
|
|
98
|
+
*/
|
|
99
|
+
/**
|
|
100
|
+
* Template tags an app writes without importing them. Each compiles exactly like the marker
|
|
101
|
+
* it names; a module that binds the name itself keeps its own meaning.
|
|
102
|
+
*/
|
|
103
|
+
export const TAG_INTRINSICS = {
|
|
104
|
+
$html: { export: 'html', module: '@fluixi/core' },
|
|
105
|
+
$svg: { export: 'svg', module: '@fluixi/core' },
|
|
106
|
+
$css: { export: 'css', module: '@fluixi/core' },
|
|
107
|
+
};
|
|
108
|
+
/** The `$` tags this module can use: all of them, less the ones it binds. */
|
|
109
|
+
export function tagIntrinsics(bound) {
|
|
110
|
+
const tags = new Map();
|
|
111
|
+
for (const [name, tag] of Object.entries(TAG_INTRINSICS))
|
|
112
|
+
if (!bound.has(name))
|
|
113
|
+
tags.set(name, tag.export);
|
|
114
|
+
return tags;
|
|
115
|
+
}
|
|
116
|
+
const INTRINSIC_CALL = new RegExp(`\\$(?:${Object.keys(INTRINSICS).map((n) => n.slice(1)).join('|')})\\s*\\(`);
|
|
117
|
+
export function mayHaveIntrinsic(code) {
|
|
118
|
+
return INTRINSIC_CALL.test(code);
|
|
119
|
+
}
|
|
120
|
+
export function isIntrinsicName(name) {
|
|
121
|
+
return Object.prototype.hasOwnProperty.call(INTRINSICS, name);
|
|
122
|
+
}
|
|
123
|
+
/** Whether a module path exports the reactive primitives. */
|
|
124
|
+
export function isPrimitiveModule(source) {
|
|
125
|
+
return PRIMITIVE_MODULES.includes(source);
|
|
126
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// src/analyze/intrinsics.ts
|
|
2
|
+
var REACTIVE_MODULE = "@fluixi/reactive/signal";
|
|
3
|
+
var INTRINSICS = {
|
|
4
|
+
$signal: { export: "signal", module: REACTIVE_MODULE, returns: "signal-handle" },
|
|
5
|
+
$memo: { export: "memo", module: REACTIVE_MODULE, returns: "memo-handle" },
|
|
6
|
+
$effect: { export: "effect", module: REACTIVE_MODULE, returns: "effect" },
|
|
7
|
+
$store: { export: "store", module: "@fluixi/reactive/store", returns: "store-handle" },
|
|
8
|
+
$resource: { export: "resource", module: REACTIVE_MODULE, returns: "resource-handle" },
|
|
9
|
+
$cachedResource: { export: "cachedResource", module: "@fluixi/reactive/cached-resource", returns: "resource-handle" },
|
|
10
|
+
// No short runtime form for these yet, so the intrinsic stands for the `create*`
|
|
11
|
+
// name. Still worth having: no import to write, and when a shorter form is
|
|
12
|
+
// designed, the change is this line rather than a compiler pass.
|
|
13
|
+
$selector: { export: "createSelector", module: REACTIVE_MODULE, returns: "memo-accessor" },
|
|
14
|
+
$deferred: { export: "createDeferred", module: REACTIVE_MODULE, returns: "memo-accessor" },
|
|
15
|
+
// Not value constructors, but the compiler has to know them: they change what a read
|
|
16
|
+
// does. `untrack` suppresses dependency collection, which is exactly the kind of thing
|
|
17
|
+
// dependency analysis must not guess at.
|
|
18
|
+
$untrack: { export: "untrack", module: REACTIVE_MODULE, returns: "plain" },
|
|
19
|
+
$untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" },
|
|
20
|
+
// Scopes, scheduling and lifecycle: no value to classify, but the same authoring promise,
|
|
21
|
+
// no import to write. `$cleanup` registers a callback on the current owner (`onCleanup`).
|
|
22
|
+
$batch: { export: "batch", module: REACTIVE_MODULE, returns: "plain" },
|
|
23
|
+
$cleanup: { export: "onCleanup", module: REACTIVE_MODULE, returns: "plain" },
|
|
24
|
+
$root: { export: "root", module: REACTIVE_MODULE, returns: "plain" },
|
|
25
|
+
$context: { export: "context", module: REACTIVE_MODULE, returns: "plain" },
|
|
26
|
+
$renderEffect: { export: "renderEffect", module: REACTIVE_MODULE, returns: "effect" },
|
|
27
|
+
$computed: { export: "computed", module: REACTIVE_MODULE, returns: "effect" },
|
|
28
|
+
// Storage for where the code runs, and a signal kept in it. `$persisted` is a signal
|
|
29
|
+
// handle as far as reads go: the same accessor with `set` on it.
|
|
30
|
+
$storage: { export: "useStorage", module: "@fluixi/core/storage", returns: "plain" },
|
|
31
|
+
$asyncStorage: { export: "useAsyncStorage", module: "@fluixi/core/storage", returns: "plain" },
|
|
32
|
+
$persisted: { export: "persisted", module: "@fluixi/core/storage", returns: "signal-handle" },
|
|
33
|
+
// An environment variable, public or server-only; the browser build refuses a secret.
|
|
34
|
+
$env: { export: "env", module: "@fluixi/start/env", returns: "plain" }
|
|
35
|
+
};
|
|
36
|
+
var RUNTIME_PRIMITIVES = {
|
|
37
|
+
signal: "signal-handle",
|
|
38
|
+
memo: "memo-handle",
|
|
39
|
+
effect: "effect",
|
|
40
|
+
store: "store-handle",
|
|
41
|
+
createSignal: ["signal-accessor", "signal-setter"],
|
|
42
|
+
createMemo: "memo-accessor",
|
|
43
|
+
createEffect: "effect",
|
|
44
|
+
createRenderEffect: "effect",
|
|
45
|
+
renderEffect: "effect",
|
|
46
|
+
computed: "effect",
|
|
47
|
+
createStore: "reactive-object",
|
|
48
|
+
resource: "resource-handle",
|
|
49
|
+
cachedResource: "resource-handle",
|
|
50
|
+
createResource: "reactive-object",
|
|
51
|
+
createSelector: "memo-accessor",
|
|
52
|
+
createDeferred: "memo-accessor"
|
|
53
|
+
};
|
|
54
|
+
var PRIMITIVE_MODULES = [
|
|
55
|
+
"@fluixi/reactive",
|
|
56
|
+
"@fluixi/reactive/signal",
|
|
57
|
+
"@fluixi/reactive/store",
|
|
58
|
+
"@fluixi/reactive/cached-resource",
|
|
59
|
+
"@fluixi/core"
|
|
60
|
+
];
|
|
61
|
+
var TAG_INTRINSICS = {
|
|
62
|
+
$html: { export: "html", module: "@fluixi/core" },
|
|
63
|
+
$svg: { export: "svg", module: "@fluixi/core" },
|
|
64
|
+
$css: { export: "css", module: "@fluixi/core" }
|
|
65
|
+
};
|
|
66
|
+
function tagIntrinsics(bound) {
|
|
67
|
+
const tags = /* @__PURE__ */ new Map();
|
|
68
|
+
for (const [name, tag] of Object.entries(TAG_INTRINSICS)) if (!bound.has(name)) tags.set(name, tag.export);
|
|
69
|
+
return tags;
|
|
70
|
+
}
|
|
71
|
+
var INTRINSIC_CALL = new RegExp(`\\$(?:${Object.keys(INTRINSICS).map((n) => n.slice(1)).join("|")})\\s*\\(`);
|
|
72
|
+
function mayHaveIntrinsic(code) {
|
|
73
|
+
return INTRINSIC_CALL.test(code);
|
|
74
|
+
}
|
|
75
|
+
function isIntrinsicName(name) {
|
|
76
|
+
return Object.prototype.hasOwnProperty.call(INTRINSICS, name);
|
|
77
|
+
}
|
|
78
|
+
function isPrimitiveModule(source) {
|
|
79
|
+
return PRIMITIVE_MODULES.includes(source);
|
|
80
|
+
}
|
|
81
|
+
export {
|
|
82
|
+
INTRINSICS,
|
|
83
|
+
PRIMITIVE_MODULES,
|
|
84
|
+
REACTIVE_MODULE,
|
|
85
|
+
RUNTIME_PRIMITIVES,
|
|
86
|
+
TAG_INTRINSICS,
|
|
87
|
+
isIntrinsicName,
|
|
88
|
+
isPrimitiveModule,
|
|
89
|
+
mayHaveIntrinsic,
|
|
90
|
+
tagIntrinsics
|
|
91
|
+
};
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/analyze/paren.ts
|
|
21
|
+
var paren_exports = {};
|
|
22
|
+
__export(paren_exports, {
|
|
23
|
+
paren: () => paren,
|
|
24
|
+
topLevelComma: () => topLevelComma
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(paren_exports);
|
|
27
|
+
function skipQuoted(src, start) {
|
|
28
|
+
const quote = src[start];
|
|
29
|
+
for (let i = start + 1; i < src.length; i++) {
|
|
30
|
+
const c = src[i];
|
|
31
|
+
if (c === "\\") i++;
|
|
32
|
+
else if (c === quote) return i + 1;
|
|
33
|
+
else if (c === "\n") return -1;
|
|
34
|
+
}
|
|
35
|
+
return -1;
|
|
36
|
+
}
|
|
37
|
+
function skipTemplate(src, start) {
|
|
38
|
+
let i = start + 1;
|
|
39
|
+
while (i < src.length) {
|
|
40
|
+
const c = src[i];
|
|
41
|
+
if (c === "\\") {
|
|
42
|
+
i += 2;
|
|
43
|
+
} else if (c === "`") {
|
|
44
|
+
return i + 1;
|
|
45
|
+
} else if (c === "$" && src[i + 1] === "{") {
|
|
46
|
+
let depth = 1;
|
|
47
|
+
i += 2;
|
|
48
|
+
while (i < src.length && depth > 0) {
|
|
49
|
+
const k = src[i];
|
|
50
|
+
if (k === "\\") i += 2;
|
|
51
|
+
else if (k === "`") {
|
|
52
|
+
const end = skipTemplate(src, i);
|
|
53
|
+
if (end < 0) return -1;
|
|
54
|
+
i = end;
|
|
55
|
+
} else if (k === '"' || k === "'") {
|
|
56
|
+
const end = skipQuoted(src, i);
|
|
57
|
+
if (end < 0) return -1;
|
|
58
|
+
i = end;
|
|
59
|
+
} else {
|
|
60
|
+
if (k === "{") depth++;
|
|
61
|
+
else if (k === "}") depth--;
|
|
62
|
+
i++;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
} else {
|
|
66
|
+
i++;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return -1;
|
|
70
|
+
}
|
|
71
|
+
function skipRegex(src, start) {
|
|
72
|
+
let inClass = false;
|
|
73
|
+
for (let i = start + 1; i < src.length; i++) {
|
|
74
|
+
const c = src[i];
|
|
75
|
+
if (c === "\\") i++;
|
|
76
|
+
else if (c === "[") inClass = true;
|
|
77
|
+
else if (c === "]") inClass = false;
|
|
78
|
+
else if (c === "\n") return -1;
|
|
79
|
+
else if (c === "/" && !inClass) {
|
|
80
|
+
let end = i + 1;
|
|
81
|
+
while (end < src.length && /[a-z]/i.test(src[end])) end++;
|
|
82
|
+
return end;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return -1;
|
|
86
|
+
}
|
|
87
|
+
function divides(prev) {
|
|
88
|
+
return prev !== "" && /[A-Za-z0-9_$)\]]/.test(prev);
|
|
89
|
+
}
|
|
90
|
+
function topLevelComma(src) {
|
|
91
|
+
let depth = 0;
|
|
92
|
+
let prev = "";
|
|
93
|
+
let i = 0;
|
|
94
|
+
while (i < src.length) {
|
|
95
|
+
const c = src[i];
|
|
96
|
+
if (c === '"' || c === "'") {
|
|
97
|
+
const end = skipQuoted(src, i);
|
|
98
|
+
if (end < 0) return null;
|
|
99
|
+
i = end;
|
|
100
|
+
prev = c;
|
|
101
|
+
} else if (c === "`") {
|
|
102
|
+
const end = skipTemplate(src, i);
|
|
103
|
+
if (end < 0) return null;
|
|
104
|
+
i = end;
|
|
105
|
+
prev = c;
|
|
106
|
+
} else if (c === "/" && src[i + 1] === "/") {
|
|
107
|
+
return null;
|
|
108
|
+
} else if (c === "/" && src[i + 1] === "*") {
|
|
109
|
+
const end = src.indexOf("*/", i + 2);
|
|
110
|
+
if (end < 0) return null;
|
|
111
|
+
i = end + 2;
|
|
112
|
+
} else if (c === "/" && !divides(prev)) {
|
|
113
|
+
const end = skipRegex(src, i);
|
|
114
|
+
if (end < 0) return null;
|
|
115
|
+
i = end;
|
|
116
|
+
prev = "/";
|
|
117
|
+
} else {
|
|
118
|
+
if (c === "(" || c === "[" || c === "{") depth++;
|
|
119
|
+
else if (c === ")" || c === "]" || c === "}") {
|
|
120
|
+
depth--;
|
|
121
|
+
if (depth < 0) return null;
|
|
122
|
+
} else if (c === "," && depth === 0) return true;
|
|
123
|
+
if (!/\s/.test(c)) prev = c;
|
|
124
|
+
i++;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return depth === 0 ? false : null;
|
|
128
|
+
}
|
|
129
|
+
function paren(code, position) {
|
|
130
|
+
const src = code.trim();
|
|
131
|
+
if (src === "") return `(${code})`;
|
|
132
|
+
if (position === "arrowBody" && src[0] === "{") return `(${code})`;
|
|
133
|
+
return topLevelComma(src) === false ? code : `(${code})`;
|
|
134
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether a raw expression slice has to be wrapped in parens before it is dropped
|
|
3
|
+
* into an object value, an argument list, a `return`, or an arrow's concise body.
|
|
4
|
+
*
|
|
5
|
+
* The compiler holds expressions as source text: `IRExpression.code` is deliberately
|
|
6
|
+
* a string (see ir/nodes.ts), so there is no printer to ask about precedence and the
|
|
7
|
+
* decision comes from the characters.
|
|
8
|
+
*
|
|
9
|
+
* Two things bind wrong. A top-level comma reads as a sequence or as an argument
|
|
10
|
+
* separator, and a leading `{` in an arrow body reads as a block. Everything else
|
|
11
|
+
* parses the same wrapped or bare.
|
|
12
|
+
*
|
|
13
|
+
* Wrapping unconditionally was the old answer, and it reached production: esbuild's
|
|
14
|
+
* minifier keeps redundant parens. Measured on the fluixi-ui playground, 3,320 of
|
|
15
|
+
* the 3,322 bytes the native build ran over the babel one were these.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* True when the text has a comma outside every bracket, string and substitution.
|
|
19
|
+
* Null when the scan cannot say, which the caller reads as "assume it does".
|
|
20
|
+
*/
|
|
21
|
+
export declare function topLevelComma(src: string): boolean | null;
|
|
22
|
+
/** Wrap a raw expression slice only where the characters say it has to be. */
|
|
23
|
+
export declare function paren(code: string, position: 'value' | 'arrowBody'): string;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether a raw expression slice has to be wrapped in parens before it is dropped
|
|
3
|
+
* into an object value, an argument list, a `return`, or an arrow's concise body.
|
|
4
|
+
*
|
|
5
|
+
* The compiler holds expressions as source text: `IRExpression.code` is deliberately
|
|
6
|
+
* a string (see ir/nodes.ts), so there is no printer to ask about precedence and the
|
|
7
|
+
* decision comes from the characters.
|
|
8
|
+
*
|
|
9
|
+
* Two things bind wrong. A top-level comma reads as a sequence or as an argument
|
|
10
|
+
* separator, and a leading `{` in an arrow body reads as a block. Everything else
|
|
11
|
+
* parses the same wrapped or bare.
|
|
12
|
+
*
|
|
13
|
+
* Wrapping unconditionally was the old answer, and it reached production: esbuild's
|
|
14
|
+
* minifier keeps redundant parens. Measured on the fluixi-ui playground, 3,320 of
|
|
15
|
+
* the 3,322 bytes the native build ran over the babel one were these.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* True when the text has a comma outside every bracket, string and substitution.
|
|
19
|
+
* Null when the scan cannot say, which the caller reads as "assume it does".
|
|
20
|
+
*/
|
|
21
|
+
export declare function topLevelComma(src: string): boolean | null;
|
|
22
|
+
/** Wrap a raw expression slice only where the characters say it has to be. */
|
|
23
|
+
export declare function paren(code: string, position: 'value' | 'arrowBody'): string;
|
|
24
|
+
//# sourceMappingURL=paren.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paren.d.ts","sourceRoot":"","sources":["../../src/analyze/paren.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAyEH;;;GAGG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAuCzD;AAED,8EAA8E;AAC9E,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,WAAW,GAAG,MAAM,CAK3E"}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether a raw expression slice has to be wrapped in parens before it is dropped
|
|
3
|
+
* into an object value, an argument list, a `return`, or an arrow's concise body.
|
|
4
|
+
*
|
|
5
|
+
* The compiler holds expressions as source text: `IRExpression.code` is deliberately
|
|
6
|
+
* a string (see ir/nodes.ts), so there is no printer to ask about precedence and the
|
|
7
|
+
* decision comes from the characters.
|
|
8
|
+
*
|
|
9
|
+
* Two things bind wrong. A top-level comma reads as a sequence or as an argument
|
|
10
|
+
* separator, and a leading `{` in an arrow body reads as a block. Everything else
|
|
11
|
+
* parses the same wrapped or bare.
|
|
12
|
+
*
|
|
13
|
+
* Wrapping unconditionally was the old answer, and it reached production: esbuild's
|
|
14
|
+
* minifier keeps redundant parens. Measured on the fluixi-ui playground, 3,320 of
|
|
15
|
+
* the 3,322 bytes the native build ran over the babel one were these.
|
|
16
|
+
*/
|
|
17
|
+
/** Index just past the closing quote, or -1 if the literal never closes. */
|
|
18
|
+
function skipQuoted(src, start) {
|
|
19
|
+
const quote = src[start];
|
|
20
|
+
for (let i = start + 1; i < src.length; i++) {
|
|
21
|
+
const c = src[i];
|
|
22
|
+
if (c === '\\')
|
|
23
|
+
i++;
|
|
24
|
+
else if (c === quote)
|
|
25
|
+
return i + 1;
|
|
26
|
+
else if (c === '\n')
|
|
27
|
+
return -1;
|
|
28
|
+
}
|
|
29
|
+
return -1;
|
|
30
|
+
}
|
|
31
|
+
/** Index just past the closing backtick. Substitutions nest, so this recurses. */
|
|
32
|
+
function skipTemplate(src, start) {
|
|
33
|
+
let i = start + 1;
|
|
34
|
+
while (i < src.length) {
|
|
35
|
+
const c = src[i];
|
|
36
|
+
if (c === '\\') {
|
|
37
|
+
i += 2;
|
|
38
|
+
}
|
|
39
|
+
else if (c === '`') {
|
|
40
|
+
return i + 1;
|
|
41
|
+
}
|
|
42
|
+
else if (c === '$' && src[i + 1] === '{') {
|
|
43
|
+
let depth = 1;
|
|
44
|
+
i += 2;
|
|
45
|
+
while (i < src.length && depth > 0) {
|
|
46
|
+
const k = src[i];
|
|
47
|
+
if (k === '\\')
|
|
48
|
+
i += 2;
|
|
49
|
+
else if (k === '`') {
|
|
50
|
+
const end = skipTemplate(src, i);
|
|
51
|
+
if (end < 0)
|
|
52
|
+
return -1;
|
|
53
|
+
i = end;
|
|
54
|
+
}
|
|
55
|
+
else if (k === '"' || k === "'") {
|
|
56
|
+
const end = skipQuoted(src, i);
|
|
57
|
+
if (end < 0)
|
|
58
|
+
return -1;
|
|
59
|
+
i = end;
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
if (k === '{')
|
|
63
|
+
depth++;
|
|
64
|
+
else if (k === '}')
|
|
65
|
+
depth--;
|
|
66
|
+
i++;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
i++;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return -1;
|
|
75
|
+
}
|
|
76
|
+
/** Index just past a regex literal's flags, or -1. */
|
|
77
|
+
function skipRegex(src, start) {
|
|
78
|
+
let inClass = false;
|
|
79
|
+
for (let i = start + 1; i < src.length; i++) {
|
|
80
|
+
const c = src[i];
|
|
81
|
+
if (c === '\\')
|
|
82
|
+
i++;
|
|
83
|
+
else if (c === '[')
|
|
84
|
+
inClass = true;
|
|
85
|
+
else if (c === ']')
|
|
86
|
+
inClass = false;
|
|
87
|
+
else if (c === '\n')
|
|
88
|
+
return -1;
|
|
89
|
+
else if (c === '/' && !inClass) {
|
|
90
|
+
let end = i + 1;
|
|
91
|
+
while (end < src.length && /[a-z]/i.test(src[end]))
|
|
92
|
+
end++;
|
|
93
|
+
return end;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return -1;
|
|
97
|
+
}
|
|
98
|
+
/** A `/` after one of these divides; anywhere else it opens a regex. */
|
|
99
|
+
function divides(prev) {
|
|
100
|
+
return prev !== '' && /[A-Za-z0-9_$)\]]/.test(prev);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* True when the text has a comma outside every bracket, string and substitution.
|
|
104
|
+
* Null when the scan cannot say, which the caller reads as "assume it does".
|
|
105
|
+
*/
|
|
106
|
+
export function topLevelComma(src) {
|
|
107
|
+
let depth = 0;
|
|
108
|
+
let prev = '';
|
|
109
|
+
let i = 0;
|
|
110
|
+
while (i < src.length) {
|
|
111
|
+
const c = src[i];
|
|
112
|
+
if (c === '"' || c === "'") {
|
|
113
|
+
const end = skipQuoted(src, i);
|
|
114
|
+
if (end < 0)
|
|
115
|
+
return null;
|
|
116
|
+
i = end;
|
|
117
|
+
prev = c;
|
|
118
|
+
}
|
|
119
|
+
else if (c === '`') {
|
|
120
|
+
const end = skipTemplate(src, i);
|
|
121
|
+
if (end < 0)
|
|
122
|
+
return null;
|
|
123
|
+
i = end;
|
|
124
|
+
prev = c;
|
|
125
|
+
}
|
|
126
|
+
else if (c === '/' && src[i + 1] === '/') {
|
|
127
|
+
// A line comment swallows whatever follows it, and a wrapper is no help.
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
else if (c === '/' && src[i + 1] === '*') {
|
|
131
|
+
const end = src.indexOf('*/', i + 2);
|
|
132
|
+
if (end < 0)
|
|
133
|
+
return null;
|
|
134
|
+
i = end + 2;
|
|
135
|
+
}
|
|
136
|
+
else if (c === '/' && !divides(prev)) {
|
|
137
|
+
const end = skipRegex(src, i);
|
|
138
|
+
if (end < 0)
|
|
139
|
+
return null;
|
|
140
|
+
i = end;
|
|
141
|
+
prev = '/';
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
if (c === '(' || c === '[' || c === '{')
|
|
145
|
+
depth++;
|
|
146
|
+
else if (c === ')' || c === ']' || c === '}') {
|
|
147
|
+
depth--;
|
|
148
|
+
if (depth < 0)
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
else if (c === ',' && depth === 0)
|
|
152
|
+
return true;
|
|
153
|
+
if (!/\s/.test(c))
|
|
154
|
+
prev = c;
|
|
155
|
+
i++;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return depth === 0 ? false : null;
|
|
159
|
+
}
|
|
160
|
+
/** Wrap a raw expression slice only where the characters say it has to be. */
|
|
161
|
+
export function paren(code, position) {
|
|
162
|
+
const src = code.trim();
|
|
163
|
+
if (src === '')
|
|
164
|
+
return `(${code})`;
|
|
165
|
+
if (position === 'arrowBody' && src[0] === '{')
|
|
166
|
+
return `(${code})`;
|
|
167
|
+
return topLevelComma(src) === false ? code : `(${code})`;
|
|
168
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
// src/analyze/paren.ts
|
|
2
|
+
function skipQuoted(src, start) {
|
|
3
|
+
const quote = src[start];
|
|
4
|
+
for (let i = start + 1; i < src.length; i++) {
|
|
5
|
+
const c = src[i];
|
|
6
|
+
if (c === "\\") i++;
|
|
7
|
+
else if (c === quote) return i + 1;
|
|
8
|
+
else if (c === "\n") return -1;
|
|
9
|
+
}
|
|
10
|
+
return -1;
|
|
11
|
+
}
|
|
12
|
+
function skipTemplate(src, start) {
|
|
13
|
+
let i = start + 1;
|
|
14
|
+
while (i < src.length) {
|
|
15
|
+
const c = src[i];
|
|
16
|
+
if (c === "\\") {
|
|
17
|
+
i += 2;
|
|
18
|
+
} else if (c === "`") {
|
|
19
|
+
return i + 1;
|
|
20
|
+
} else if (c === "$" && src[i + 1] === "{") {
|
|
21
|
+
let depth = 1;
|
|
22
|
+
i += 2;
|
|
23
|
+
while (i < src.length && depth > 0) {
|
|
24
|
+
const k = src[i];
|
|
25
|
+
if (k === "\\") i += 2;
|
|
26
|
+
else if (k === "`") {
|
|
27
|
+
const end = skipTemplate(src, i);
|
|
28
|
+
if (end < 0) return -1;
|
|
29
|
+
i = end;
|
|
30
|
+
} else if (k === '"' || k === "'") {
|
|
31
|
+
const end = skipQuoted(src, i);
|
|
32
|
+
if (end < 0) return -1;
|
|
33
|
+
i = end;
|
|
34
|
+
} else {
|
|
35
|
+
if (k === "{") depth++;
|
|
36
|
+
else if (k === "}") depth--;
|
|
37
|
+
i++;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
} else {
|
|
41
|
+
i++;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return -1;
|
|
45
|
+
}
|
|
46
|
+
function skipRegex(src, start) {
|
|
47
|
+
let inClass = false;
|
|
48
|
+
for (let i = start + 1; i < src.length; i++) {
|
|
49
|
+
const c = src[i];
|
|
50
|
+
if (c === "\\") i++;
|
|
51
|
+
else if (c === "[") inClass = true;
|
|
52
|
+
else if (c === "]") inClass = false;
|
|
53
|
+
else if (c === "\n") return -1;
|
|
54
|
+
else if (c === "/" && !inClass) {
|
|
55
|
+
let end = i + 1;
|
|
56
|
+
while (end < src.length && /[a-z]/i.test(src[end])) end++;
|
|
57
|
+
return end;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return -1;
|
|
61
|
+
}
|
|
62
|
+
function divides(prev) {
|
|
63
|
+
return prev !== "" && /[A-Za-z0-9_$)\]]/.test(prev);
|
|
64
|
+
}
|
|
65
|
+
function topLevelComma(src) {
|
|
66
|
+
let depth = 0;
|
|
67
|
+
let prev = "";
|
|
68
|
+
let i = 0;
|
|
69
|
+
while (i < src.length) {
|
|
70
|
+
const c = src[i];
|
|
71
|
+
if (c === '"' || c === "'") {
|
|
72
|
+
const end = skipQuoted(src, i);
|
|
73
|
+
if (end < 0) return null;
|
|
74
|
+
i = end;
|
|
75
|
+
prev = c;
|
|
76
|
+
} else if (c === "`") {
|
|
77
|
+
const end = skipTemplate(src, i);
|
|
78
|
+
if (end < 0) return null;
|
|
79
|
+
i = end;
|
|
80
|
+
prev = c;
|
|
81
|
+
} else if (c === "/" && src[i + 1] === "/") {
|
|
82
|
+
return null;
|
|
83
|
+
} else if (c === "/" && src[i + 1] === "*") {
|
|
84
|
+
const end = src.indexOf("*/", i + 2);
|
|
85
|
+
if (end < 0) return null;
|
|
86
|
+
i = end + 2;
|
|
87
|
+
} else if (c === "/" && !divides(prev)) {
|
|
88
|
+
const end = skipRegex(src, i);
|
|
89
|
+
if (end < 0) return null;
|
|
90
|
+
i = end;
|
|
91
|
+
prev = "/";
|
|
92
|
+
} else {
|
|
93
|
+
if (c === "(" || c === "[" || c === "{") depth++;
|
|
94
|
+
else if (c === ")" || c === "]" || c === "}") {
|
|
95
|
+
depth--;
|
|
96
|
+
if (depth < 0) return null;
|
|
97
|
+
} else if (c === "," && depth === 0) return true;
|
|
98
|
+
if (!/\s/.test(c)) prev = c;
|
|
99
|
+
i++;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return depth === 0 ? false : null;
|
|
103
|
+
}
|
|
104
|
+
function paren(code, position) {
|
|
105
|
+
const src = code.trim();
|
|
106
|
+
if (src === "") return `(${code})`;
|
|
107
|
+
if (position === "arrowBody" && src[0] === "{") return `(${code})`;
|
|
108
|
+
return topLevelComma(src) === false ? code : `(${code})`;
|
|
109
|
+
}
|
|
110
|
+
export {
|
|
111
|
+
paren,
|
|
112
|
+
topLevelComma
|
|
113
|
+
};
|