@bleedingdev/modern-js-renderer-octane 0.0.0-stage → 3.9.3-ultramodern.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/LICENSE +21 -0
- package/bin/octane-tsc.mjs +4 -0
- package/dist/cjs/bootstrap.js +68 -0
- package/dist/cjs/client.js +371 -0
- package/dist/cjs/entry-application.js +83 -0
- package/dist/cjs/entry-client.js +92 -0
- package/dist/cjs/entry-server.js +127 -0
- package/dist/cjs/federation-context.js +72 -0
- package/dist/cjs/federation.js +103 -0
- package/dist/cjs/i18n/I18nProvider.js +67 -0
- package/dist/cjs/i18n/LocalizedLink.js +89 -0
- package/dist/cjs/i18n/context.js +41 -0
- package/dist/cjs/i18n/index.js +86 -0
- package/dist/cjs/i18n/languageSync.js +99 -0
- package/dist/cjs/i18n/types.js +18 -0
- package/dist/cjs/i18n/useI18n.js +110 -0
- package/dist/cjs/index.js +46 -0
- package/dist/cjs/manifest.js +167 -0
- package/dist/cjs/plugin/compiler.js +125 -0
- package/dist/cjs/plugin/create.js +265 -0
- package/dist/cjs/plugin/index.js +151 -0
- package/dist/cjs/plugin/profile.js +89 -0
- package/dist/cjs/plugin/source.js +56 -0
- package/dist/cjs/router-client.js +139 -0
- package/dist/cjs/router-handler.js +168 -0
- package/dist/cjs/router-injection.js +139 -0
- package/dist/cjs/router-server-cleanup.js +46 -0
- package/dist/cjs/router-server-snapshot.js +405 -0
- package/dist/cjs/router-server.js +108 -0
- package/dist/cjs/router-snapshot.js +270 -0
- package/dist/cjs/router.js +218 -0
- package/dist/cjs/routes.js +187 -0
- package/dist/cjs/server.js +224 -0
- package/dist/cjs/typecheck.js +615 -0
- package/dist/esm/bootstrap.mjs +24 -0
- package/dist/esm/client.mjs +327 -0
- package/dist/esm/entry-application.mjs +39 -0
- package/dist/esm/entry-client.mjs +54 -0
- package/dist/esm/entry-server.mjs +86 -0
- package/dist/esm/federation-context.mjs +25 -0
- package/dist/esm/federation.mjs +65 -0
- package/dist/esm/i18n/I18nProvider.mjs +29 -0
- package/dist/esm/i18n/LocalizedLink.mjs +48 -0
- package/dist/esm/i18n/context.mjs +3 -0
- package/dist/esm/i18n/index.mjs +8 -0
- package/dist/esm/i18n/languageSync.mjs +61 -0
- package/dist/esm/i18n/types.mjs +0 -0
- package/dist/esm/i18n/useI18n.mjs +72 -0
- package/dist/esm/index.mjs +8 -0
- package/dist/esm/manifest.mjs +117 -0
- package/dist/esm/router-client.mjs +98 -0
- package/dist/esm/router-handler.mjs +130 -0
- package/dist/esm/router-injection.mjs +101 -0
- package/dist/esm/router-server-cleanup.mjs +8 -0
- package/dist/esm/router-server-snapshot.mjs +367 -0
- package/dist/esm/router-server.mjs +12 -0
- package/dist/esm/router-snapshot.mjs +199 -0
- package/dist/esm/router.mjs +94 -0
- package/dist/esm/routes.mjs +134 -0
- package/dist/esm/server.mjs +183 -0
- package/dist/esm-node/bootstrap.mjs +24 -0
- package/dist/esm-node/manifest.mjs +117 -0
- package/dist/esm-node/plugin/compiler.mjs +70 -0
- package/dist/esm-node/plugin/create.mjs +227 -0
- package/dist/esm-node/plugin/index.mjs +103 -0
- package/dist/esm-node/plugin/profile.mjs +51 -0
- package/dist/esm-node/plugin/source.mjs +7 -0
- package/dist/esm-node/typecheck.mjs +560 -0
- package/dist/types/bootstrap.d.ts +10 -0
- package/dist/types/client.d.ts +36 -0
- package/dist/types/entry-application.d.ts +19 -0
- package/dist/types/entry-client.d.ts +8 -0
- package/dist/types/entry-server.d.ts +11 -0
- package/dist/types/federation-context.d.ts +28 -0
- package/dist/types/federation.d.ts +18 -0
- package/dist/types/i18n/I18nProvider.d.ts +8 -0
- package/dist/types/i18n/LocalizedLink.d.ts +41 -0
- package/dist/types/i18n/context.d.ts +9 -0
- package/dist/types/i18n/index.d.ts +9 -0
- package/dist/types/i18n/languageSync.d.ts +26 -0
- package/dist/types/i18n/types.d.ts +34 -0
- package/dist/types/i18n/useI18n.d.ts +21 -0
- package/dist/types/index.d.ts +9 -0
- package/dist/types/manifest.d.ts +34 -0
- package/dist/types/plugin/compiler-manifest.d.cts +10 -0
- package/dist/types/plugin/compiler.d.ts +5 -0
- package/dist/types/plugin/create.d.ts +23 -0
- package/dist/types/plugin/index.d.ts +3 -0
- package/dist/types/plugin/profile.d.ts +2 -0
- package/dist/types/plugin/source.d.ts +1 -0
- package/dist/types/plugin/svg-component-template.d.cts +6 -0
- package/dist/types/router-client.d.ts +12 -0
- package/dist/types/router-handler.d.ts +13 -0
- package/dist/types/router-injection.d.ts +8 -0
- package/dist/types/router-server-cleanup.d.ts +3 -0
- package/dist/types/router-server-snapshot.d.ts +15 -0
- package/dist/types/router-server.d.ts +13 -0
- package/dist/types/router-snapshot.d.ts +14 -0
- package/dist/types/router.d.ts +30 -0
- package/dist/types/routes.d.ts +18 -0
- package/dist/types/server.d.ts +41 -0
- package/dist/types/typecheck.d.ts +31 -0
- package/package.json +216 -4
- package/src/bootstrap.ts +60 -0
- package/src/client.ts +485 -0
- package/src/entry-application.ts +72 -0
- package/src/entry-client.ts +80 -0
- package/src/entry-server.ts +142 -0
- package/src/federation-context.ts +53 -0
- package/src/federation.ts +158 -0
- package/src/i18n/I18nProvider.ts +56 -0
- package/src/i18n/LocalizedLink.ts +112 -0
- package/src/i18n/context.ts +12 -0
- package/src/i18n/index.ts +35 -0
- package/src/i18n/languageSync.ts +132 -0
- package/src/i18n/types.ts +36 -0
- package/src/i18n/useI18n.ts +119 -0
- package/src/index.ts +10 -0
- package/src/manifest.ts +253 -0
- package/src/plugin/compiler-manifest.cjs +178 -0
- package/src/plugin/compiler.ts +112 -0
- package/src/plugin/create.ts +272 -0
- package/src/plugin/index.ts +105 -0
- package/src/plugin/profile.ts +46 -0
- package/src/plugin/source.ts +16 -0
- package/src/plugin/svg-component-template.cjs +17 -0
- package/src/router-client.ts +144 -0
- package/src/router-handler.ts +182 -0
- package/src/router-injection.ts +145 -0
- package/src/router-server-cleanup.ts +11 -0
- package/src/router-server-snapshot.ts +564 -0
- package/src/router-server.ts +23 -0
- package/src/router-snapshot.ts +251 -0
- package/src/router.ts +192 -0
- package/src/routes.ts +263 -0
- package/src/server.ts +300 -0
- package/src/typecheck.ts +723 -0
- package/README.md +0 -3
|
@@ -0,0 +1,560 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import node_fs from "node:fs";
|
|
3
|
+
import node_path from "node:path";
|
|
4
|
+
import { SourceMap, shouldReportDiagnostics } from "@volar/language-core";
|
|
5
|
+
import { findNodeAtLocation, getNodeValue, parse, parseTree } from "jsonc-parser";
|
|
6
|
+
import { compileToVolarMappings } from "octane/compiler/volar";
|
|
7
|
+
import { version } from "typescript";
|
|
8
|
+
import { createVirtualFileSystem } from "typescript/unstable/fs";
|
|
9
|
+
import { API } from "typescript/unstable/sync";
|
|
10
|
+
const nativeExtension = /\.tsrx$/u;
|
|
11
|
+
const projectedExtension = /\.tsrx\.tsx$/u;
|
|
12
|
+
function typecheck_location(source, pos) {
|
|
13
|
+
const prefix = source.slice(0, pos);
|
|
14
|
+
const lines = prefix.split(/\r\n|\r|\n/u);
|
|
15
|
+
return {
|
|
16
|
+
line: lines.length,
|
|
17
|
+
column: (lines.at(-1)?.length ?? 0) + 1
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function readFile(file) {
|
|
21
|
+
try {
|
|
22
|
+
return node_fs.readFileSync(file, 'utf8');
|
|
23
|
+
} catch (error) {
|
|
24
|
+
if (error instanceof Error && 'code' in error && ('ENOENT' === error.code || 'ENOTDIR' === error.code)) return;
|
|
25
|
+
throw error;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function projectConfig(source, fileName, discovery, roots) {
|
|
29
|
+
const errors = [];
|
|
30
|
+
const config = parseTree(source.replace(/^\uFEFF/u, ' '), errors, {
|
|
31
|
+
allowTrailingComma: true
|
|
32
|
+
});
|
|
33
|
+
if (errors.length || !config || 'object' !== config.type) return;
|
|
34
|
+
const edits = [];
|
|
35
|
+
const additions = [];
|
|
36
|
+
for (const field of [
|
|
37
|
+
'files',
|
|
38
|
+
'include',
|
|
39
|
+
'exclude'
|
|
40
|
+
]){
|
|
41
|
+
const array = findNodeAtLocation(config, [
|
|
42
|
+
field
|
|
43
|
+
]);
|
|
44
|
+
if (roots) {
|
|
45
|
+
const content = JSON.stringify('files' === field ? roots : []);
|
|
46
|
+
if (array) {
|
|
47
|
+
if ('array' === array.type && (array.children ?? []).every((node)=>'string' === node.type)) edits.push({
|
|
48
|
+
offset: array.offset,
|
|
49
|
+
length: array.length,
|
|
50
|
+
content
|
|
51
|
+
});
|
|
52
|
+
} else additions.push(`${JSON.stringify(field)}:${content}`);
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (array?.type === 'array') for (const node of array.children ?? []){
|
|
56
|
+
const file = getNodeValue(node);
|
|
57
|
+
if ('string' != typeof file) continue;
|
|
58
|
+
const projected = 'files' === field || 'complete' === discovery ? nativeExtension.test(file) ? `${file}.tsx` : file : 'native' === discovery && /[.*?]/u.test(file.replaceAll('\\', '/').split('/').at(-1) ?? '') ? `${file.endsWith('/**') ? `${file}/*` : file}.tsx` : file;
|
|
59
|
+
if (projected !== file) edits.push({
|
|
60
|
+
offset: node.offset,
|
|
61
|
+
length: node.length,
|
|
62
|
+
content: JSON.stringify(projected)
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (additions.length) edits.push({
|
|
67
|
+
offset: config.offset + 1,
|
|
68
|
+
length: 0,
|
|
69
|
+
content: `${additions.join(',')}${config.children?.length ? ',' : ''}`
|
|
70
|
+
});
|
|
71
|
+
if (!edits.length) return;
|
|
72
|
+
const mappings = [];
|
|
73
|
+
let sourceOffset = 0;
|
|
74
|
+
let code = '';
|
|
75
|
+
for (const edit of edits.sort((left, right)=>left.offset - right.offset)){
|
|
76
|
+
const unchanged = source.slice(sourceOffset, edit.offset);
|
|
77
|
+
mappings.push({
|
|
78
|
+
sourceOffsets: [
|
|
79
|
+
sourceOffset
|
|
80
|
+
],
|
|
81
|
+
generatedOffsets: [
|
|
82
|
+
code.length
|
|
83
|
+
],
|
|
84
|
+
lengths: [
|
|
85
|
+
unchanged.length
|
|
86
|
+
],
|
|
87
|
+
data: {
|
|
88
|
+
verification: true
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
code += unchanged;
|
|
92
|
+
mappings.push({
|
|
93
|
+
sourceOffsets: [
|
|
94
|
+
edit.offset
|
|
95
|
+
],
|
|
96
|
+
generatedOffsets: [
|
|
97
|
+
code.length
|
|
98
|
+
],
|
|
99
|
+
lengths: [
|
|
100
|
+
edit.length
|
|
101
|
+
],
|
|
102
|
+
generatedLengths: [
|
|
103
|
+
edit.content.length
|
|
104
|
+
],
|
|
105
|
+
data: {
|
|
106
|
+
verification: true
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
code += edit.content;
|
|
110
|
+
sourceOffset = edit.offset + edit.length;
|
|
111
|
+
}
|
|
112
|
+
mappings.push({
|
|
113
|
+
sourceOffsets: [
|
|
114
|
+
sourceOffset
|
|
115
|
+
],
|
|
116
|
+
generatedOffsets: [
|
|
117
|
+
code.length
|
|
118
|
+
],
|
|
119
|
+
lengths: [
|
|
120
|
+
source.length - sourceOffset
|
|
121
|
+
],
|
|
122
|
+
data: {
|
|
123
|
+
verification: true
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
code += source.slice(sourceOffset);
|
|
127
|
+
return {
|
|
128
|
+
source,
|
|
129
|
+
fileName,
|
|
130
|
+
code,
|
|
131
|
+
map: new SourceMap(mappings)
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
function diagnosticText(diagnostic) {
|
|
135
|
+
return [
|
|
136
|
+
diagnostic.text,
|
|
137
|
+
...diagnostic.messageChain?.map(diagnosticText) ?? []
|
|
138
|
+
].join('\n');
|
|
139
|
+
}
|
|
140
|
+
function checkOctaneProject(options) {
|
|
141
|
+
if ('7.0.2' !== version) throw new Error(`Octane typechecking requires TypeScript 7.0.2; found ${version}`);
|
|
142
|
+
const cwd = node_path.resolve(options.cwd ?? process.cwd());
|
|
143
|
+
let project = node_path.resolve(cwd, options.project);
|
|
144
|
+
if (node_fs.existsSync(project) && node_fs.statSync(project).isDirectory()) project = node_path.join(project, 'tsconfig.json');
|
|
145
|
+
if (!node_fs.existsSync(project)) throw new Error(`Cannot find project ${project}`);
|
|
146
|
+
if (options.compilerOptions?.noEmit === false || options.compilerOptions?.noCheck === true || options.compilerOptions?.skipLibCheck === true || options.compilerOptions?.skipDefaultLibCheck === true) throw new Error('Octane typechecking requires noEmit, full checking, and library checking');
|
|
147
|
+
const effectiveConfig = node_path.join(node_path.dirname(project), `.octane-typecheck-${randomUUID()}.json`);
|
|
148
|
+
const authoredConfig = parse((readFile(project) ?? '').replace(/^\uFEFF/u, ' '), [], {
|
|
149
|
+
allowTrailingComma: true
|
|
150
|
+
});
|
|
151
|
+
const effectiveOptions = {
|
|
152
|
+
extends: project,
|
|
153
|
+
...Array.isArray(authoredConfig?.references) ? {
|
|
154
|
+
references: authoredConfig.references
|
|
155
|
+
} : {},
|
|
156
|
+
compilerOptions: {
|
|
157
|
+
...options.compilerOptions,
|
|
158
|
+
noEmit: true,
|
|
159
|
+
noCheck: false,
|
|
160
|
+
skipLibCheck: false,
|
|
161
|
+
skipDefaultLibCheck: false
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
const virtual = createVirtualFileSystem({
|
|
165
|
+
[effectiveConfig]: JSON.stringify(effectiveOptions)
|
|
166
|
+
});
|
|
167
|
+
const projections = new Map();
|
|
168
|
+
const configurations = new Map();
|
|
169
|
+
const configFiles = new Set([
|
|
170
|
+
project
|
|
171
|
+
]);
|
|
172
|
+
const referencedConfigs = new Set([
|
|
173
|
+
project
|
|
174
|
+
]);
|
|
175
|
+
const referenceRoots = new Map();
|
|
176
|
+
let discovery = 'ordinary';
|
|
177
|
+
function authoredName(file) {
|
|
178
|
+
if (!projectedExtension.test(file)) return file;
|
|
179
|
+
const authored = file.slice(0, -4);
|
|
180
|
+
if (!node_fs.existsSync(authored)) return file;
|
|
181
|
+
if (node_fs.existsSync(file)) throw new Error(`Octane projection collision: ${authored} conflicts with physical ${file}`);
|
|
182
|
+
return authored;
|
|
183
|
+
}
|
|
184
|
+
function projection(file) {
|
|
185
|
+
const fileName = authoredName(file);
|
|
186
|
+
if (fileName === file) return;
|
|
187
|
+
const known = projections.get(file);
|
|
188
|
+
if (known) return known;
|
|
189
|
+
const source = readFile(fileName);
|
|
190
|
+
if (void 0 === source) return;
|
|
191
|
+
let compiled;
|
|
192
|
+
try {
|
|
193
|
+
compiled = compileToVolarMappings(source, fileName, {
|
|
194
|
+
loose: true
|
|
195
|
+
});
|
|
196
|
+
} catch (error) {
|
|
197
|
+
if (!(error instanceof SyntaxError)) throw error;
|
|
198
|
+
compiled = {
|
|
199
|
+
code: 'export {};',
|
|
200
|
+
mappings: [],
|
|
201
|
+
diagnostics: [],
|
|
202
|
+
errors: [
|
|
203
|
+
{
|
|
204
|
+
name: error.name,
|
|
205
|
+
message: error.message,
|
|
206
|
+
fileName,
|
|
207
|
+
type: 'fatal',
|
|
208
|
+
...'pos' in error && 'number' == typeof error.pos ? {
|
|
209
|
+
pos: error.pos
|
|
210
|
+
} : {},
|
|
211
|
+
...'end' in error && 'number' == typeof error.end ? {
|
|
212
|
+
end: error.end
|
|
213
|
+
} : {}
|
|
214
|
+
}
|
|
215
|
+
]
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
const result = {
|
|
219
|
+
...compiled,
|
|
220
|
+
source,
|
|
221
|
+
fileName,
|
|
222
|
+
map: new SourceMap(compiled.mappings)
|
|
223
|
+
};
|
|
224
|
+
projections.set(file, result);
|
|
225
|
+
virtual.writeFile?.(file, compiled.code);
|
|
226
|
+
return result;
|
|
227
|
+
}
|
|
228
|
+
const overlay = {
|
|
229
|
+
readFile (file) {
|
|
230
|
+
const content = virtual.readFile?.(file);
|
|
231
|
+
if (void 0 !== content) return content;
|
|
232
|
+
const compiled = projection(file);
|
|
233
|
+
if (compiled) return compiled.code;
|
|
234
|
+
if (file.endsWith('.json')) {
|
|
235
|
+
const source = readFile(file);
|
|
236
|
+
if (void 0 !== source) {
|
|
237
|
+
if (!configFiles.has(file) && ('complete' === discovery || 'package.json' === node_path.basename(file))) return source;
|
|
238
|
+
configFiles.add(file);
|
|
239
|
+
const configData = parse(source.replace(/^\uFEFF/u, ' '), [], {
|
|
240
|
+
allowTrailingComma: true
|
|
241
|
+
});
|
|
242
|
+
for (const reference of referencedConfigs.has(file) && Array.isArray(configData?.references) ? configData.references : []){
|
|
243
|
+
if ('string' != typeof reference?.path) continue;
|
|
244
|
+
const target = node_path.resolve(node_path.dirname(file), reference.path);
|
|
245
|
+
const referenceFile = target.endsWith('.json') ? target : node_path.join(target, 'tsconfig.json');
|
|
246
|
+
configFiles.add(referenceFile);
|
|
247
|
+
referencedConfigs.add(referenceFile);
|
|
248
|
+
}
|
|
249
|
+
const roots = 'complete' === discovery ? referenceRoots.get(file) : void 0;
|
|
250
|
+
const config = projectConfig(source, file, discovery, roots ? [
|
|
251
|
+
...roots
|
|
252
|
+
] : void 0);
|
|
253
|
+
if (config) configurations.set(file, config);
|
|
254
|
+
else configurations.delete(file);
|
|
255
|
+
return config?.code ?? source;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
},
|
|
259
|
+
fileExists (file) {
|
|
260
|
+
if (virtual.fileExists?.(file)) return true;
|
|
261
|
+
if (authoredName(file) !== file) return true;
|
|
262
|
+
},
|
|
263
|
+
directoryExists (directory) {
|
|
264
|
+
return virtual.directoryExists?.(directory) || void 0;
|
|
265
|
+
},
|
|
266
|
+
getAccessibleEntries (directory) {
|
|
267
|
+
const files = new Set(virtual.getAccessibleEntries?.(directory)?.files);
|
|
268
|
+
const directories = new Set(virtual.getAccessibleEntries?.(directory)?.directories);
|
|
269
|
+
try {
|
|
270
|
+
for (const entry of node_fs.readdirSync(directory, {
|
|
271
|
+
withFileTypes: true
|
|
272
|
+
})){
|
|
273
|
+
let isDirectory = entry.isDirectory();
|
|
274
|
+
if (entry.isSymbolicLink()) try {
|
|
275
|
+
isDirectory = node_fs.statSync(node_path.join(directory, entry.name)).isDirectory();
|
|
276
|
+
} catch (error) {
|
|
277
|
+
if (error instanceof Error && 'code' in error && ('ENOENT' === error.code || 'ENOTDIR' === error.code)) continue;
|
|
278
|
+
throw error;
|
|
279
|
+
}
|
|
280
|
+
if (isDirectory) directories.add(entry.name);
|
|
281
|
+
else {
|
|
282
|
+
files.add(entry.name);
|
|
283
|
+
if (nativeExtension.test(entry.name)) {
|
|
284
|
+
const projected = node_path.join(directory, `${entry.name}.tsx`);
|
|
285
|
+
authoredName(projected);
|
|
286
|
+
files.add(`${entry.name}.tsx`);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
} catch (error) {
|
|
291
|
+
if (!(error instanceof Error && 'code' in error && ('ENOENT' === error.code || 'ENOTDIR' === error.code))) throw error;
|
|
292
|
+
}
|
|
293
|
+
return {
|
|
294
|
+
files: [
|
|
295
|
+
...files
|
|
296
|
+
].filter((file)=>'ordinary' !== discovery || authoredName(node_path.join(directory, file)) === node_path.join(directory, file)).sort(),
|
|
297
|
+
directories: [
|
|
298
|
+
...directories
|
|
299
|
+
].sort()
|
|
300
|
+
};
|
|
301
|
+
},
|
|
302
|
+
realpath (file) {
|
|
303
|
+
const authored = authoredName(file);
|
|
304
|
+
if (authored !== file) try {
|
|
305
|
+
return `${node_fs.realpathSync(authored)}.tsx`;
|
|
306
|
+
} catch {
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
return virtual.fileExists?.(file) ? file : void 0;
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
const roots = new Set();
|
|
313
|
+
for (const mode of [
|
|
314
|
+
'ordinary',
|
|
315
|
+
'native'
|
|
316
|
+
]){
|
|
317
|
+
discovery = mode;
|
|
318
|
+
const parser = new API({
|
|
319
|
+
cwd,
|
|
320
|
+
fs: overlay
|
|
321
|
+
});
|
|
322
|
+
try {
|
|
323
|
+
for (const file of parser.parseConfigFile(effectiveConfig).fileNames)if ('ordinary' === mode || authoredName(file) !== file) roots.add(file);
|
|
324
|
+
const parsedReferences = new Set([
|
|
325
|
+
project
|
|
326
|
+
]);
|
|
327
|
+
for (const reference of referencedConfigs){
|
|
328
|
+
if (parsedReferences.has(reference)) continue;
|
|
329
|
+
parsedReferences.add(reference);
|
|
330
|
+
const selected = referenceRoots.get(reference) ?? new Set();
|
|
331
|
+
referenceRoots.set(reference, selected);
|
|
332
|
+
for (const file of parser.parseConfigFile(reference).fileNames)if ('ordinary' === mode || authoredName(file) !== file) selected.add(file);
|
|
333
|
+
}
|
|
334
|
+
} finally{
|
|
335
|
+
parser.close();
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
discovery = 'complete';
|
|
339
|
+
virtual.writeFile?.(effectiveConfig, JSON.stringify({
|
|
340
|
+
...effectiveOptions,
|
|
341
|
+
files: [
|
|
342
|
+
...roots
|
|
343
|
+
],
|
|
344
|
+
include: [],
|
|
345
|
+
exclude: []
|
|
346
|
+
}));
|
|
347
|
+
const api = new API({
|
|
348
|
+
cwd,
|
|
349
|
+
fs: overlay
|
|
350
|
+
});
|
|
351
|
+
try {
|
|
352
|
+
const snapshot = api.updateSnapshot({
|
|
353
|
+
openProjects: [
|
|
354
|
+
effectiveConfig
|
|
355
|
+
],
|
|
356
|
+
openFiles: [
|
|
357
|
+
...roots
|
|
358
|
+
]
|
|
359
|
+
});
|
|
360
|
+
const program = snapshot.getProject(effectiveConfig)?.program;
|
|
361
|
+
if (!program) throw new Error(`Native TypeScript did not load project ${project}`);
|
|
362
|
+
function remap(diagnostic) {
|
|
363
|
+
const relatedInformation = diagnostic.relatedInformation?.flatMap((info)=>{
|
|
364
|
+
const mapped = remap(info);
|
|
365
|
+
return mapped ? [
|
|
366
|
+
mapped
|
|
367
|
+
] : [];
|
|
368
|
+
});
|
|
369
|
+
const text = diagnosticText(diagnostic);
|
|
370
|
+
const compiled = diagnostic.fileName ? projections.get(diagnostic.fileName) ?? configurations.get(diagnostic.fileName) : void 0;
|
|
371
|
+
let pos = diagnostic.pos;
|
|
372
|
+
let end = diagnostic.end;
|
|
373
|
+
let origin = "typescript";
|
|
374
|
+
let message = text;
|
|
375
|
+
if (compiled) {
|
|
376
|
+
const ranges = compiled.map.toSourceRange(pos, end, true, (info)=>shouldReportDiagnostics(info, void 0, diagnostic.code));
|
|
377
|
+
const range = ranges.next().value;
|
|
378
|
+
if (range) [pos, end] = range;
|
|
379
|
+
else {
|
|
380
|
+
if (!compiled.map.toSourceRange(pos, end, true).next().done) return;
|
|
381
|
+
origin = 'projection';
|
|
382
|
+
message = `Cannot map native TS${diagnostic.code} at generated offsets ${pos}-${end}: ${text}`;
|
|
383
|
+
pos = 0;
|
|
384
|
+
end = 0;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
const fileName = compiled?.fileName ?? (diagnostic.fileName === effectiveConfig ? void 0 : diagnostic.fileName);
|
|
388
|
+
const source = compiled?.source ?? (fileName ? readFile(fileName) : void 0);
|
|
389
|
+
return {
|
|
390
|
+
...fileName ? {
|
|
391
|
+
fileName
|
|
392
|
+
} : {},
|
|
393
|
+
pos,
|
|
394
|
+
end,
|
|
395
|
+
...void 0 !== source ? typecheck_location(source, pos) : {},
|
|
396
|
+
code: diagnostic.code,
|
|
397
|
+
category: 'projection' === origin || 1 === diagnostic.category ? 'error' : 0 === diagnostic.category ? 'warning' : 'message',
|
|
398
|
+
text: message,
|
|
399
|
+
origin,
|
|
400
|
+
...relatedInformation?.length ? {
|
|
401
|
+
relatedInformation
|
|
402
|
+
} : {}
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
const diagnostics = [
|
|
406
|
+
...program.getConfigFileParsingDiagnostics(),
|
|
407
|
+
...program.getProgramDiagnostics(),
|
|
408
|
+
...program.getGlobalDiagnostics(),
|
|
409
|
+
...program.getSyntacticDiagnostics(),
|
|
410
|
+
...program.getBindDiagnostics(),
|
|
411
|
+
...program.getSemanticDiagnostics()
|
|
412
|
+
].flatMap((diagnostic)=>{
|
|
413
|
+
const mapped = remap(diagnostic);
|
|
414
|
+
return mapped ? [
|
|
415
|
+
mapped
|
|
416
|
+
] : [];
|
|
417
|
+
});
|
|
418
|
+
const nativeFiles = program.getSourceFileNames();
|
|
419
|
+
for (const file of nativeFiles){
|
|
420
|
+
const compiled = projections.get(file);
|
|
421
|
+
if (compiled) {
|
|
422
|
+
for (const diagnostic of compiled.diagnostics)diagnostics.push({
|
|
423
|
+
fileName: compiled.fileName,
|
|
424
|
+
pos: diagnostic.start.offset,
|
|
425
|
+
end: diagnostic.end.offset,
|
|
426
|
+
...typecheck_location(compiled.source, diagnostic.start.offset),
|
|
427
|
+
code: diagnostic.code,
|
|
428
|
+
category: 'error' === diagnostic.severity ? 'error' : 'warning' === diagnostic.severity ? 'warning' : 'message',
|
|
429
|
+
text: diagnostic.message,
|
|
430
|
+
origin: 'octane'
|
|
431
|
+
});
|
|
432
|
+
for (const error of compiled.errors){
|
|
433
|
+
const pos = error.pos ?? 0;
|
|
434
|
+
diagnostics.push({
|
|
435
|
+
fileName: compiled.fileName,
|
|
436
|
+
pos,
|
|
437
|
+
end: error.end ?? pos,
|
|
438
|
+
...typecheck_location(compiled.source, pos),
|
|
439
|
+
code: 'OCTANE_PARSE',
|
|
440
|
+
category: 'error',
|
|
441
|
+
text: error.message,
|
|
442
|
+
origin: 'octane'
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
const unique = new Map(diagnostics.map((diagnostic)=>[
|
|
448
|
+
JSON.stringify(diagnostic),
|
|
449
|
+
diagnostic
|
|
450
|
+
]));
|
|
451
|
+
return {
|
|
452
|
+
compilerVersion: version,
|
|
453
|
+
files: [
|
|
454
|
+
...new Set(nativeFiles.map((file)=>projections.get(file)?.fileName ?? file))
|
|
455
|
+
].sort(),
|
|
456
|
+
diagnostics: [
|
|
457
|
+
...unique.values()
|
|
458
|
+
].sort((left, right)=>(left.fileName ?? '').localeCompare(right.fileName ?? '') || left.pos - right.pos || String(left.code).localeCompare(String(right.code)))
|
|
459
|
+
};
|
|
460
|
+
} finally{
|
|
461
|
+
api.close();
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
function formatOctaneDiagnostic(diagnostic, cwd = process.cwd()) {
|
|
465
|
+
const file = diagnostic.fileName ? `${node_path.relative(cwd, diagnostic.fileName)}(${diagnostic.line ?? 1},${diagnostic.column ?? 1}): ` : '';
|
|
466
|
+
const code = 'number' == typeof diagnostic.code ? `TS${diagnostic.code}` : diagnostic.code;
|
|
467
|
+
const related = diagnostic.relatedInformation?.map((info)=>` ${formatOctaneDiagnostic(info, cwd)}`).join('\n');
|
|
468
|
+
return `${file}${diagnostic.category} ${code}: ${diagnostic.text}${related ? `\n${related}` : ''}`;
|
|
469
|
+
}
|
|
470
|
+
const booleanOptions = new Set([
|
|
471
|
+
'strict',
|
|
472
|
+
'isolatedModules',
|
|
473
|
+
'verbatimModuleSyntax',
|
|
474
|
+
'allowImportingTsExtensions',
|
|
475
|
+
'allowJs',
|
|
476
|
+
'esModuleInterop',
|
|
477
|
+
'noUncheckedIndexedAccess',
|
|
478
|
+
'exactOptionalPropertyTypes',
|
|
479
|
+
'noImplicitOverride',
|
|
480
|
+
'noFallthroughCasesInSwitch',
|
|
481
|
+
'noPropertyAccessFromIndexSignature',
|
|
482
|
+
'noImplicitReturns',
|
|
483
|
+
'resolveJsonModule',
|
|
484
|
+
'strictNullChecks',
|
|
485
|
+
'strictFunctionTypes',
|
|
486
|
+
'strictBindCallApply',
|
|
487
|
+
'strictPropertyInitialization',
|
|
488
|
+
'noImplicitAny',
|
|
489
|
+
'noImplicitThis',
|
|
490
|
+
'useUnknownInCatchVariables',
|
|
491
|
+
'alwaysStrict'
|
|
492
|
+
]);
|
|
493
|
+
const stringOptions = new Set([
|
|
494
|
+
'target',
|
|
495
|
+
'module',
|
|
496
|
+
'moduleResolution',
|
|
497
|
+
'moduleDetection',
|
|
498
|
+
'jsx',
|
|
499
|
+
'jsxImportSource'
|
|
500
|
+
]);
|
|
501
|
+
function runOctaneTypecheck(argv, io = {}) {
|
|
502
|
+
const stdout = io.stdout ?? ((text)=>process.stdout.write(text));
|
|
503
|
+
const stderr = io.stderr ?? ((text)=>process.stderr.write(text));
|
|
504
|
+
try {
|
|
505
|
+
let project = 'tsconfig.json';
|
|
506
|
+
let listFiles = false;
|
|
507
|
+
const compilerOptions = {};
|
|
508
|
+
for(let index = 0; index < argv.length; index++){
|
|
509
|
+
const argument = argv[index];
|
|
510
|
+
if ('--version' === argument || '-v' === argument) {
|
|
511
|
+
stdout(`Version ${version}\n`);
|
|
512
|
+
return 0;
|
|
513
|
+
}
|
|
514
|
+
if ('--help' === argument || '-h' === argument) {
|
|
515
|
+
stdout('octane-tsc --project <tsconfig.json> [--noEmit] [--strict]\n');
|
|
516
|
+
return 0;
|
|
517
|
+
}
|
|
518
|
+
if ('--project' === argument || '-p' === argument) {
|
|
519
|
+
const value = argv[++index];
|
|
520
|
+
if (!value || value.startsWith('-')) throw new Error('--project requires a configuration path');
|
|
521
|
+
project = value;
|
|
522
|
+
continue;
|
|
523
|
+
}
|
|
524
|
+
if (!argument?.startsWith('--')) throw new Error(`Unsupported Octane typecheck argument ${argument}`);
|
|
525
|
+
const name = argument.slice(2);
|
|
526
|
+
if (booleanOptions.has(name) || [
|
|
527
|
+
'noEmit',
|
|
528
|
+
'noCheck',
|
|
529
|
+
'skipLibCheck',
|
|
530
|
+
'skipDefaultLibCheck',
|
|
531
|
+
'pretty',
|
|
532
|
+
'listFiles',
|
|
533
|
+
'explainFiles'
|
|
534
|
+
].includes(name)) {
|
|
535
|
+
const explicit = argv[index + 1];
|
|
536
|
+
const value = 'true' === explicit || 'false' === explicit ? 'true' === argv[++index] : true;
|
|
537
|
+
if ('noEmit' === name && !value || ('noCheck' === name || 'skipLibCheck' === name || 'skipDefaultLibCheck' === name) && value) throw new Error(`--${name} ${value} is incompatible with full Octane typechecking`);
|
|
538
|
+
if ('listFiles' === name || 'explainFiles' === name) listFiles ||= value;
|
|
539
|
+
else if ('pretty' !== name) compilerOptions[name] = value;
|
|
540
|
+
} else if (stringOptions.has(name) || 'lib' === name || 'types' === name) {
|
|
541
|
+
const value = argv[++index];
|
|
542
|
+
if (!value || value.startsWith('-')) throw new Error(`--${name} requires a value`);
|
|
543
|
+
compilerOptions[name] = 'lib' === name || 'types' === name ? value.split(',') : value;
|
|
544
|
+
} else throw new Error(`Unsupported Octane typecheck option --${name}`);
|
|
545
|
+
}
|
|
546
|
+
const cwd = node_path.resolve(io.cwd ?? process.cwd());
|
|
547
|
+
const result = checkOctaneProject({
|
|
548
|
+
project,
|
|
549
|
+
cwd,
|
|
550
|
+
compilerOptions
|
|
551
|
+
});
|
|
552
|
+
for (const diagnostic of result.diagnostics)stdout(`${formatOctaneDiagnostic(diagnostic, cwd)}\n`);
|
|
553
|
+
if (listFiles) for (const file of result.files)stdout(`${file}\n`);
|
|
554
|
+
return result.diagnostics.some((diagnostic)=>'error' === diagnostic.category) ? 1 : 0;
|
|
555
|
+
} catch (error) {
|
|
556
|
+
stderr(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
557
|
+
return 1;
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
export { checkOctaneProject, formatOctaneDiagnostic, runOctaneTypecheck };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type DocumentBootstrap } from '@modern-js/renderer-core/document';
|
|
2
|
+
import { type RendererIdentity } from '@modern-js/renderer-core/identity';
|
|
3
|
+
export interface OctaneDocumentBootstrap extends DocumentBootstrap {
|
|
4
|
+
/** Actual native client compilation hash, separate from application identity. */
|
|
5
|
+
readonly nativeHydrationBuildId: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function assertNativeHydrationBuildId(value: unknown): asserts value is string;
|
|
8
|
+
export declare function assertOctaneIdentity(identity: RendererIdentity): void;
|
|
9
|
+
/** Read the server's bootstrap and require this exact native client build. */
|
|
10
|
+
export declare function readOctaneDocumentBootstrap(document: Document, expectedIdentity: RendererIdentity, expectedNativeHydrationBuildId?: string): OctaneDocumentBootstrap;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { NativeFederationBinding } from '@modern-js/renderer-core/federation';
|
|
2
|
+
import { type RendererIdentity } from '@modern-js/renderer-core/identity';
|
|
3
|
+
import { type ComponentBody, type Root, type RootContainer, type RootOptions } from 'octane';
|
|
4
|
+
export type { OctaneDocumentBootstrap } from './bootstrap';
|
|
5
|
+
export { readOctaneDocumentBootstrap } from './bootstrap';
|
|
6
|
+
export interface OctaneApplicationModule {
|
|
7
|
+
readonly default: ComponentBody;
|
|
8
|
+
readonly props?: Record<string, unknown>;
|
|
9
|
+
/** Request-independent resources owned by this browser application module. */
|
|
10
|
+
readonly dispose?: () => void;
|
|
11
|
+
}
|
|
12
|
+
export interface OctaneApplicationHandle {
|
|
13
|
+
readonly root: Root;
|
|
14
|
+
readonly identity: Readonly<RendererIdentity>;
|
|
15
|
+
update(application: OctaneApplicationModule): void;
|
|
16
|
+
dispose(): void;
|
|
17
|
+
}
|
|
18
|
+
export interface OctaneApplicationOptions {
|
|
19
|
+
readonly container: Exclude<RootContainer, Document>;
|
|
20
|
+
readonly identity: RendererIdentity;
|
|
21
|
+
readonly nativeHydrationBuildId: string;
|
|
22
|
+
/** Cancels startup ownership and retires an active application. */
|
|
23
|
+
readonly signal?: AbortSignal;
|
|
24
|
+
/** Hydration installs the native signal bridge before invoking this importer. */
|
|
25
|
+
readonly load: () => Promise<OctaneApplicationModule>;
|
|
26
|
+
readonly options?: Omit<RootOptions, 'signalOwner'>;
|
|
27
|
+
/** This browser compilation's native Module Federation runtime. */
|
|
28
|
+
readonly federation?: NativeFederationBinding;
|
|
29
|
+
}
|
|
30
|
+
export interface OctaneHydrationOptions extends OctaneApplicationOptions {
|
|
31
|
+
readonly documentIdentity: RendererIdentity;
|
|
32
|
+
readonly documentNativeHydrationBuildId: string;
|
|
33
|
+
readonly documentId: string;
|
|
34
|
+
}
|
|
35
|
+
export declare function mountOctaneApplication(input: OctaneApplicationOptions): Promise<OctaneApplicationHandle>;
|
|
36
|
+
export declare function hydrateOctaneApplication(input: OctaneHydrationOptions): Promise<OctaneApplicationHandle>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { LocalisedUrlsOption } from '@modern-js/i18n-runtime-extensions/paths';
|
|
2
|
+
import type { NativeI18nView } from '@modern-js/renderer-core/entry-client';
|
|
3
|
+
import type { NativeRouterFactory } from '@modern-js/renderer-core/router';
|
|
4
|
+
import { type AnyRoute, type AnyRouter } from '@octanejs/tanstack-router';
|
|
5
|
+
import { type ComponentBody } from 'octane';
|
|
6
|
+
export type OctaneI18nView = NativeI18nView<unknown, LocalisedUrlsOption>;
|
|
7
|
+
/** Wrap a component entry in its request's or document's i18n provider. */
|
|
8
|
+
export declare function componentView(component: unknown, i18n?: OctaneI18nView): ComponentBody;
|
|
9
|
+
/** The Octane route tree and router of a generated entry. */
|
|
10
|
+
export declare const octaneRouterFactory: NativeRouterFactory<AnyRoute, AnyRouter>;
|
|
11
|
+
interface LocalizedRouterProps {
|
|
12
|
+
readonly router: AnyRouter;
|
|
13
|
+
readonly i18n: OctaneI18nView;
|
|
14
|
+
}
|
|
15
|
+
/** Wrap a router root in the request's or document's i18n provider. */
|
|
16
|
+
export declare function localizedRouterRoot(Root: ComponentBody<{
|
|
17
|
+
router: AnyRouter;
|
|
18
|
+
}>): ComponentBody<LocalizedRouterProps>;
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { LocalisedUrlsOption } from '@modern-js/i18n-runtime-extensions/paths';
|
|
2
|
+
import { type NativeClientEntryOptions, type NativeI18nInstance } from '@modern-js/renderer-core/entry-client';
|
|
3
|
+
export interface OctaneClientEntryOptions extends NativeClientEntryOptions<NativeI18nInstance, LocalisedUrlsOption> {
|
|
4
|
+
/** The native client compilation hash, `__webpack_hash__`. */
|
|
5
|
+
readonly nativeHydrationBuildId: string;
|
|
6
|
+
}
|
|
7
|
+
/** Start a generated Octane browser entry: mount, or hydrate the server document. */
|
|
8
|
+
export declare function startNativeClient(options: OctaneClientEntryOptions): void;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { LocalisedUrlsOption } from '@modern-js/i18n-runtime-extensions/paths';
|
|
2
|
+
import { type NativeI18nInstance, type NativeServerEntry, type NativeServerEntryOptions } from '@modern-js/renderer-core/entry-server';
|
|
3
|
+
import type { ResponsePolicy } from '@modern-js/renderer-core/session';
|
|
4
|
+
/**
|
|
5
|
+
* The loader projection strips representation fields; the ones an Octane route
|
|
6
|
+
* declares for the document itself are kept, as Solid document headers are.
|
|
7
|
+
*/
|
|
8
|
+
export declare function withOctaneDocumentFields(policy: ResponsePolicy, responseHeaders: Headers): ResponsePolicy;
|
|
9
|
+
export type OctaneServerEntryOptions = NativeServerEntryOptions<NativeI18nInstance, LocalisedUrlsOption>;
|
|
10
|
+
/** The native transport handlers of a generated Octane server entry. */
|
|
11
|
+
export declare function createNativeServerEntry(options: OctaneServerEntryOptions): NativeServerEntry;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type FederationInstance, type NativeFederationBinding } from '@modern-js/renderer-core/federation';
|
|
2
|
+
import { type ComponentBody } from 'octane';
|
|
3
|
+
/** One application owns its host runtime; each response owns its render scope. */
|
|
4
|
+
export interface OctaneFederationScope {
|
|
5
|
+
readonly instance: FederationInstance | undefined;
|
|
6
|
+
readonly server: boolean;
|
|
7
|
+
readonly nonce?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare const FederationContext: import("octane").Context<OctaneFederationScope | null>;
|
|
10
|
+
export declare function createFederationScope(binding: NativeFederationBinding | undefined, server: boolean, nonce?: string): OctaneFederationScope;
|
|
11
|
+
export declare function FederationRoot(props: {
|
|
12
|
+
readonly scope: OctaneFederationScope;
|
|
13
|
+
readonly children?: unknown;
|
|
14
|
+
}): import("octane").ElementDescriptor<{
|
|
15
|
+
value: OctaneFederationScope;
|
|
16
|
+
children: unknown;
|
|
17
|
+
}>;
|
|
18
|
+
/** A stable root component retains native state when its application updates. */
|
|
19
|
+
export declare function FederationApplication(props: {
|
|
20
|
+
readonly scope: OctaneFederationScope;
|
|
21
|
+
readonly application: {
|
|
22
|
+
readonly default: ComponentBody;
|
|
23
|
+
readonly props?: unknown;
|
|
24
|
+
};
|
|
25
|
+
}): import("octane").ElementDescriptor<{
|
|
26
|
+
scope: OctaneFederationScope;
|
|
27
|
+
children: import("octane").ElementDescriptor<unknown>;
|
|
28
|
+
}>;
|