@navita/core 0.0.0 → 0.0.2
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/createRenderer.d.ts +21 -11
- package/createRenderer.js +45 -315
- package/createRenderer.mjs +45 -298
- package/evaluateAndProcess.d.ts +32 -10
- package/evaluateAndProcess.js +254 -49
- package/evaluateAndProcess.mjs +259 -37
- package/index.d.ts +1 -22
- package/index.js +0 -53
- package/index.mjs +0 -47
- package/package.json +18 -11
package/createRenderer.mjs
CHANGED
|
@@ -1,306 +1,53 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
function
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
const newResult = (values || []).map((item)=>{
|
|
42
|
-
if (typeof item === "string") {
|
|
43
|
-
const rules = item.split(' ').map((x)=>renderer.classPropertyList.has(x) ? [
|
|
44
|
-
x,
|
|
45
|
-
[
|
|
46
|
-
...renderer.classPropertyList.get(x)
|
|
47
|
-
]
|
|
48
|
-
] : false).filter(Boolean);
|
|
49
|
-
return `new (require('@navita/css').ClassList)("${item}", ${JSON.stringify(rules)})`;
|
|
1
|
+
import { Engine } from '@navita/engine';
|
|
2
|
+
import { transformer } from '@navita/swc';
|
|
3
|
+
import { evaluateAndProcess } from './evaluateAndProcess.mjs';
|
|
4
|
+
import 'node:path';
|
|
5
|
+
import 'node:vm';
|
|
6
|
+
import 'node:fs';
|
|
7
|
+
import 'enhanced-resolve';
|
|
8
|
+
import '@navita/adapter';
|
|
9
|
+
|
|
10
|
+
function startsWithRSCDirective(content) {
|
|
11
|
+
return /^(['"])use client\1;?/.test(content);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function createRenderer({ resolver , readFile , importMap =[] , engineOptions }) {
|
|
15
|
+
const engine = new Engine(engineOptions);
|
|
16
|
+
return {
|
|
17
|
+
engine,
|
|
18
|
+
async transformAndProcess ({ content , filePath }) {
|
|
19
|
+
const [newContent, { result , dependencies }] = await Promise.all([
|
|
20
|
+
transformer(content, {
|
|
21
|
+
filename: filePath,
|
|
22
|
+
importMap
|
|
23
|
+
}),
|
|
24
|
+
evaluateAndProcess({
|
|
25
|
+
type: 'entryPoint',
|
|
26
|
+
source: content,
|
|
27
|
+
filePath,
|
|
28
|
+
resolver,
|
|
29
|
+
readFile,
|
|
30
|
+
importMap,
|
|
31
|
+
engine
|
|
32
|
+
})
|
|
33
|
+
]);
|
|
34
|
+
const finalContent = [];
|
|
35
|
+
// Check if content starts with "use client".
|
|
36
|
+
if (startsWithRSCDirective(content)) {
|
|
37
|
+
const [directive, ...restContent] = newContent.trim().split('\n');
|
|
38
|
+
finalContent.push(directive, result, ...restContent);
|
|
39
|
+
} else {
|
|
40
|
+
finalContent.push(result, newContent.trim());
|
|
50
41
|
}
|
|
51
|
-
return JSON.stringify(item);
|
|
52
|
-
});
|
|
53
|
-
return `const $$evaluatedValues = [${newResult}];`;
|
|
54
|
-
}
|
|
55
|
-
return `const $$evaluatedValues = ${JSON.stringify(values || [])};`;
|
|
56
|
-
}
|
|
57
|
-
function evaluatedResult() {
|
|
58
|
-
return (renderer)=>{
|
|
59
|
-
renderer.evaluatedResults = new Map();
|
|
60
|
-
renderer.setEvaluatedResult = (fileName, index, value)=>{
|
|
61
|
-
if (!renderer.evaluatedResults.has(fileName)) {
|
|
62
|
-
renderer.evaluatedResults.set(fileName, []);
|
|
63
|
-
}
|
|
64
|
-
renderer.evaluatedResults.get(fileName)[index] = value;
|
|
65
|
-
};
|
|
66
|
-
renderer.getResult = (filePath, isServer)=>{
|
|
67
|
-
const result = createResult(renderer, filePath, isServer || false);
|
|
68
42
|
return {
|
|
69
|
-
result,
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
43
|
+
result: finalContent.join('\n'),
|
|
44
|
+
dependencies,
|
|
45
|
+
usedIds: engine.getUsedCacheIds([
|
|
46
|
+
filePath
|
|
47
|
+
])
|
|
73
48
|
};
|
|
74
|
-
};
|
|
75
|
-
return renderer;
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
function isMediaQuery(rule) {
|
|
80
|
-
return rule.startsWith('@media');
|
|
81
|
-
}
|
|
82
|
-
function isSupportsQuery(rule) {
|
|
83
|
-
return rule.startsWith('@supports');
|
|
84
|
-
}
|
|
85
|
-
function isPseudoSelector(rule) {
|
|
86
|
-
return rule.startsWith(':');
|
|
87
|
-
}
|
|
88
|
-
function wrapWith(atRule, query, content) {
|
|
89
|
-
return query.length > 0 ? `${atRule} ${query} {${content}}` : content;
|
|
90
|
-
}
|
|
91
|
-
function createCssRule(selector, properties) {
|
|
92
|
-
return `${selector}{${properties.map((rule)=>`${cssifyProperty(rule.property)}: ${rule.value};`).join('')}}`;
|
|
93
|
-
}
|
|
94
|
-
function generateCombinedMediaQuery(currentMediaQuery, nestedMediaQuery) {
|
|
95
|
-
if (currentMediaQuery.length === 0) {
|
|
96
|
-
return nestedMediaQuery;
|
|
97
|
-
}
|
|
98
|
-
return `${currentMediaQuery} and ${nestedMediaQuery}`;
|
|
99
|
-
}
|
|
100
|
-
function cssifyProperty(property) {
|
|
101
|
-
return property.replace(/([a-zA-Z])([A-Z])/g, '$1-$2').toLowerCase();
|
|
102
|
-
}
|
|
103
|
-
function isObject(value) {
|
|
104
|
-
return typeof value === 'object' && !Array.isArray(value);
|
|
105
|
-
}
|
|
106
|
-
function collectAndGroupRules(cssObj, currentSupportsQuery = '', currentMediaQuery = '', currentPseudoSelector = '', groupedRules = {}) {
|
|
107
|
-
for (const [property, value] of Object.entries(cssObj)){
|
|
108
|
-
if (!isObject(value)) {
|
|
109
|
-
if (!groupedRules[currentSupportsQuery]) {
|
|
110
|
-
groupedRules[currentSupportsQuery] = {};
|
|
111
|
-
}
|
|
112
|
-
const supportsGroup = groupedRules[currentSupportsQuery];
|
|
113
|
-
if (!supportsGroup[currentMediaQuery]) {
|
|
114
|
-
supportsGroup[currentMediaQuery] = {};
|
|
115
|
-
}
|
|
116
|
-
const mediaGroup = supportsGroup[currentMediaQuery];
|
|
117
|
-
if (!mediaGroup[currentPseudoSelector]) {
|
|
118
|
-
mediaGroup[currentPseudoSelector] = [];
|
|
119
|
-
}
|
|
120
|
-
mediaGroup[currentPseudoSelector].push({
|
|
121
|
-
property,
|
|
122
|
-
value
|
|
123
|
-
});
|
|
124
|
-
continue;
|
|
125
|
-
}
|
|
126
|
-
if (isMediaQuery(property)) {
|
|
127
|
-
collectAndGroupRules(value, currentSupportsQuery, generateCombinedMediaQuery(currentMediaQuery, property.slice(6).trim()), currentPseudoSelector, groupedRules);
|
|
128
|
-
continue;
|
|
129
|
-
}
|
|
130
|
-
if (isSupportsQuery(property)) {
|
|
131
|
-
collectAndGroupRules(value, generateCombinedMediaQuery(currentSupportsQuery, property.slice(9).trim()), currentMediaQuery, currentPseudoSelector, groupedRules);
|
|
132
|
-
continue;
|
|
133
49
|
}
|
|
134
|
-
if (isPseudoSelector(property)) {
|
|
135
|
-
collectAndGroupRules(value, currentSupportsQuery, currentMediaQuery, currentPseudoSelector + property, groupedRules);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
return groupedRules;
|
|
139
|
-
}
|
|
140
|
-
function serializeCss(selector, cssObj) {
|
|
141
|
-
const processPseudoSelectors = (pseudoSelectors)=>Object.entries(pseudoSelectors).map(([pseudo, properties])=>createCssRule(`${selector}${pseudo}`, properties)).join('');
|
|
142
|
-
const processMediaQueries = (mediaQueries)=>Object.entries(mediaQueries).map(([media, pseudoSelectors])=>wrapWith('@media', media, processPseudoSelectors(pseudoSelectors))).join('');
|
|
143
|
-
const rules = collectAndGroupRules(cssObj);
|
|
144
|
-
return Object.entries(rules).map(([supports, mediaQueries])=>wrapWith('@supports', supports, processMediaQueries(mediaQueries))).join('');
|
|
145
|
-
}
|
|
146
|
-
function nestedStatic() {
|
|
147
|
-
// Fela doesn't handle nested static styles correctly. This is a workaround for now.
|
|
148
|
-
// https://github.com/robinweser/fela/issues/876
|
|
149
|
-
// https://github.com/robinweser/fela/issues/465#issuecomment-594396150
|
|
150
|
-
// https://github.com/robinweser/fela/issues/863
|
|
151
|
-
return (renderer)=>{
|
|
152
|
-
const { renderStatic } = renderer;
|
|
153
|
-
renderer.renderStatic = (staticStyle, selector)=>{
|
|
154
|
-
return renderStatic(serializeCss(selector, staticStyle), undefined);
|
|
155
|
-
};
|
|
156
|
-
return renderer;
|
|
157
|
-
};
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
function renderToString() {
|
|
161
|
-
return (renderer)=>{
|
|
162
|
-
renderer.renderToString = (fileName)=>{
|
|
163
|
-
if (!renderer.getScopedCache || !renderer.accessedKeys) {
|
|
164
|
-
return renderToString$1(renderer);
|
|
165
|
-
}
|
|
166
|
-
if (fileName) {
|
|
167
|
-
return renderToString$1({
|
|
168
|
-
...renderer,
|
|
169
|
-
cache: renderer.getScopedCache(fileName)
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
const newCache = {};
|
|
173
|
-
for (const keys of renderer.accessedKeys.values()){
|
|
174
|
-
for (const key of keys){
|
|
175
|
-
const item = renderer.cache[key];
|
|
176
|
-
if (!item) {
|
|
177
|
-
continue;
|
|
178
|
-
}
|
|
179
|
-
newCache[key] = item;
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
return renderToString$1({
|
|
183
|
-
...renderer,
|
|
184
|
-
cache: newCache
|
|
185
|
-
});
|
|
186
|
-
};
|
|
187
|
-
return renderer;
|
|
188
50
|
};
|
|
189
51
|
}
|
|
190
52
|
|
|
191
|
-
function scopedCache() {
|
|
192
|
-
return (renderer)=>{
|
|
193
|
-
let currentFileName;
|
|
194
|
-
const ensureCache = ()=>{
|
|
195
|
-
if (isProxy(renderer.cache)) {
|
|
196
|
-
return;
|
|
197
|
-
}
|
|
198
|
-
renderer.cache = new Proxy(renderer.cache, {
|
|
199
|
-
getOwnPropertyDescriptor (target, key) {
|
|
200
|
-
const result = Reflect.getOwnPropertyDescriptor(target, key);
|
|
201
|
-
const { accessedKeys } = renderer;
|
|
202
|
-
if (!currentFileName) {
|
|
203
|
-
return result;
|
|
204
|
-
}
|
|
205
|
-
if (!accessedKeys.has(currentFileName)) {
|
|
206
|
-
accessedKeys.set(currentFileName, new Set());
|
|
207
|
-
}
|
|
208
|
-
accessedKeys.get(currentFileName)?.add(key);
|
|
209
|
-
return result;
|
|
210
|
-
}
|
|
211
|
-
});
|
|
212
|
-
};
|
|
213
|
-
renderer.setFilePath = (filePath)=>{
|
|
214
|
-
currentFileName = filePath;
|
|
215
|
-
// After we've set the file path, we need to ensure that the cache is a proxy,
|
|
216
|
-
// and set up to record accessed keys.
|
|
217
|
-
// Without a filePath, the proxy on the cache doesn't make sense, so this is a good place to do it.
|
|
218
|
-
ensureCache();
|
|
219
|
-
};
|
|
220
|
-
renderer.accessedKeys = new Map();
|
|
221
|
-
renderer.clearAccessedKeys = (filePath)=>{
|
|
222
|
-
renderer.accessedKeys.get(filePath)?.clear();
|
|
223
|
-
};
|
|
224
|
-
renderer.getScopedCache = (filePath)=>{
|
|
225
|
-
const { accessedKeys } = renderer;
|
|
226
|
-
const newCache = {};
|
|
227
|
-
if (accessedKeys.has(filePath)) {
|
|
228
|
-
const keys = accessedKeys.get(filePath);
|
|
229
|
-
for (const key of keys){
|
|
230
|
-
const item = renderer.cache[key];
|
|
231
|
-
if (!item) {
|
|
232
|
-
continue;
|
|
233
|
-
}
|
|
234
|
-
newCache[key] = item;
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
return newCache;
|
|
238
|
-
};
|
|
239
|
-
renderer.classPropertyList = new Map();
|
|
240
|
-
renderer.subscribe((message)=>{
|
|
241
|
-
if (message.type === 'RULE') {
|
|
242
|
-
const { declaration , className } = message;
|
|
243
|
-
const [property] = declaration.split(':');
|
|
244
|
-
if (!property) {
|
|
245
|
-
return;
|
|
246
|
-
}
|
|
247
|
-
const { classPropertyList } = renderer;
|
|
248
|
-
if (!classPropertyList.has(className)) {
|
|
249
|
-
classPropertyList.set(className, new Set());
|
|
250
|
-
}
|
|
251
|
-
classPropertyList.get(className)?.add(property);
|
|
252
|
-
}
|
|
253
|
-
});
|
|
254
|
-
return renderer;
|
|
255
|
-
};
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
function serializedCache(keys = []) {
|
|
259
|
-
return (renderer)=>{
|
|
260
|
-
renderer.serialize = ()=>{
|
|
261
|
-
const obj = {};
|
|
262
|
-
for (const key of keys){
|
|
263
|
-
const value = renderer[key];
|
|
264
|
-
if (isProxy(value)) {
|
|
265
|
-
obj[key] = Object.assign({}, value);
|
|
266
|
-
} else {
|
|
267
|
-
obj[key] = value;
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
return v8.serialize(obj).toString('base64');
|
|
271
|
-
};
|
|
272
|
-
renderer.deserialize = (serialized)=>{
|
|
273
|
-
if (!serialized) {
|
|
274
|
-
return;
|
|
275
|
-
}
|
|
276
|
-
const data = v8.deserialize(Buffer.from(serialized, 'base64'));
|
|
277
|
-
for (const [key, value] of Object.entries(data)){
|
|
278
|
-
renderer[key] = value;
|
|
279
|
-
}
|
|
280
|
-
};
|
|
281
|
-
return renderer;
|
|
282
|
-
};
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
function createRenderer() {
|
|
286
|
-
return createRenderer$1({
|
|
287
|
-
enhancers: [
|
|
288
|
-
className([
|
|
289
|
-
'ad'
|
|
290
|
-
]),
|
|
291
|
-
scopedCache(),
|
|
292
|
-
serializedCache([
|
|
293
|
-
'cache',
|
|
294
|
-
'classPropertyList',
|
|
295
|
-
'accessedKeys',
|
|
296
|
-
'uniqueRuleIdentifier',
|
|
297
|
-
'uniqueKeyframeIdentifier'
|
|
298
|
-
]),
|
|
299
|
-
evaluatedResult(),
|
|
300
|
-
renderToString(),
|
|
301
|
-
nestedStatic()
|
|
302
|
-
]
|
|
303
|
-
});
|
|
304
|
-
}
|
|
305
|
-
|
|
306
53
|
export { createRenderer };
|
package/evaluateAndProcess.d.ts
CHANGED
|
@@ -1,14 +1,36 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import '
|
|
3
|
-
import '@navita/types';
|
|
1
|
+
import { Engine } from '@navita/engine';
|
|
2
|
+
import { ImportMap } from '@navita/types';
|
|
4
3
|
|
|
5
|
-
|
|
4
|
+
type FilePath = string;
|
|
5
|
+
type ResolverCache = Record<FilePath, unknown>;
|
|
6
|
+
type NodeModuleCache = Record<FilePath, unknown>;
|
|
7
|
+
|
|
8
|
+
type FilePathWithType = string;
|
|
9
|
+
type ModuleCache = Map<FilePathWithType, {
|
|
6
10
|
source: string;
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
+
compiledFn: () => Promise<{
|
|
12
|
+
dependencies: string[];
|
|
13
|
+
exports: Record<string, unknown>;
|
|
14
|
+
}>;
|
|
15
|
+
}>;
|
|
16
|
+
interface Caches {
|
|
17
|
+
nodeModuleCache?: NodeModuleCache;
|
|
18
|
+
resolverCache?: ResolverCache;
|
|
19
|
+
moduleCache?: ModuleCache;
|
|
20
|
+
}
|
|
21
|
+
type Types = 'entryPoint' | 'dependency';
|
|
22
|
+
interface Output<Type extends Types> {
|
|
23
|
+
result: Type extends 'entryPoint' ? string : Record<string, unknown>;
|
|
24
|
+
dependencies: string[];
|
|
11
25
|
}
|
|
12
|
-
declare function evaluateAndProcess({ source,
|
|
26
|
+
declare function evaluateAndProcess<Type extends 'entryPoint' | 'dependency'>({ type, filePath, source, engine, resolver, readFile, importMap, nodeModuleCache, resolverCache, moduleCache, }: {
|
|
27
|
+
source: string;
|
|
28
|
+
filePath: string;
|
|
29
|
+
type: Type;
|
|
30
|
+
engine: Engine;
|
|
31
|
+
resolver: (filePath: string, request: string) => Promise<string>;
|
|
32
|
+
readFile: (filePath: string) => Promise<string>;
|
|
33
|
+
importMap: ImportMap;
|
|
34
|
+
} & Caches): Promise<Output<Type>>;
|
|
13
35
|
|
|
14
|
-
export { evaluateAndProcess };
|
|
36
|
+
export { Caches, evaluateAndProcess };
|