@@ -1,7 +1,7 @@
|
|
1
1
|
|
2
2
|
|
3
3
|
|
4
|
-
module.exports.getMeta = function
|
4
|
+
module.exports.getMeta = function() {
|
5
5
|
const workingDirectory = process.cwd();
|
6
6
|
const needleConfig = require(workingDirectory + "/needle.config.json");
|
7
7
|
if (needleConfig.codegenDirectory) {
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import { loadConfig } from "./config.js";
|
2
|
-
import { tryGetNeedleEngineVersion } from "
|
2
|
+
import { tryGetNeedleEngineVersion } from "../common/version.js";
|
3
3
|
|
4
4
|
// NOTE: ALL DEFINES MUST BE SET HERE! NEVER ADD OR RELY ON DEFINES IN ANY OTHER PLUGIN
|
5
5
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import { loadConfig } from './config.js';
|
2
2
|
import fs from 'fs';
|
3
3
|
import { getPosterPath } from './poster.js';
|
4
|
-
import { tryGetNeedleEngineVersion } from '
|
4
|
+
import { tryGetNeedleEngineVersion } from '../common/version.js';
|
5
5
|
|
6
6
|
/**
|
7
7
|
* @param {import('../types').userSettings} userSettings
|
@@ -1,5 +1,8 @@
|
|
1
1
|
import { fileURLToPath } from 'url';
|
2
2
|
import { dirname, resolve } from 'path';
|
3
|
+
import { tryGetNeedleEngineVersion } from '../common/version.js';
|
4
|
+
import { tryGetGenerator } from '../common/generator.js';
|
5
|
+
import { getMeta } from '../common/config.cjs';
|
3
6
|
// import { ApplyLicensePlugin } from './license.js';
|
4
7
|
|
5
8
|
const __filename = fileURLToPath(import.meta.url);
|
@@ -34,20 +37,21 @@
|
|
34
37
|
}
|
35
38
|
/** @param {import ('next').NextConfig config } */
|
36
39
|
function nextWebPack(config, { buildId, dev, isServer, defaultLoaders, webpack }) {
|
40
|
+
const meta = getMeta();
|
41
|
+
let useRapier = userSettings?.useRapier ?? meta?.useRapier === false ?? true;
|
37
42
|
// add defines
|
38
43
|
const webpackModule = userSettings.modules?.webpack;
|
39
44
|
const definePlugin = webpackModule && new webpackModule.DefinePlugin({
|
40
|
-
|
41
|
-
|
45
|
+
NEEDLE_ENGINE_VERSION: JSON.stringify(tryGetNeedleEngineVersion() ?? "0.0.0"),
|
46
|
+
NEEDLE_ENGINE_GENERATOR: JSON.stringify(tryGetGenerator() ?? "unknown"),
|
47
|
+
NEEDLE_USE_RAPIER: JSON.stringify(useRapier),
|
48
|
+
// TODO globalThis is not solved via DefinePlugin
|
42
49
|
parcelRequire: undefined,
|
43
50
|
});
|
44
51
|
if (!definePlugin) console.log("WARN: no define plugin provided. Did you miss adding the webpack module to the next config? You can pass it to the Needle plugins via `nextConfig.modules = { webpack };`");
|
45
52
|
else
|
46
53
|
config.plugins.push(definePlugin);
|
47
54
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
55
|
if (!config.module) config.module = {};
|
52
56
|
if (!config.module.rules) config.module.rules = [];
|
53
57
|
// add license plugin
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import { TypeStore } from "./../engine_typestore"
|
2
|
-
|
2
|
+
|
3
3
|
// Import types
|
4
4
|
import { __Ignore } from "../../engine-components/codegen/components";
|
5
5
|
import { ActionBuilder } from "../../engine-components/export/usdz/extensions/behavior/BehavioursBuilder";
|
@@ -217,7 +217,7 @@
|
|
217
217
|
import { XRGrabRendering } from "../../engine-components/webxr/WebXRGrabRendering";
|
218
218
|
import { XRRig } from "../../engine-components/webxr/WebXRRig";
|
219
219
|
import { XRState } from "../../engine-components/XRFlag";
|
220
|
-
|
220
|
+
|
221
221
|
// Register types
|
222
222
|
TypeStore.add("__Ignore", __Ignore);
|
223
223
|
TypeStore.add("ActionBuilder", ActionBuilder);
|
@@ -1,11 +0,0 @@
|
|
1
|
-
import { existsSync, readFileSync } from "fs";
|
2
|
-
|
3
|
-
export function tryGetNeedleEngineVersion() {
|
4
|
-
const needleEnginePackageJsonPath = process.cwd() + "/node_modules/@needle-tools/engine/package.json";
|
5
|
-
if (existsSync(needleEnginePackageJsonPath)) {
|
6
|
-
const json = JSON.parse(readFileSync(needleEnginePackageJsonPath));
|
7
|
-
const version = json.version;
|
8
|
-
return version;
|
9
|
-
}
|
10
|
-
return null;
|
11
|
-
}
|
@@ -337,7 +337,7 @@
|
|
337
337
|
|
338
338
|
state = this.getState(state, layerIndex) as State;
|
339
339
|
|
340
|
-
if (!state?.motion || !state.motion.clip) {
|
340
|
+
if (!state?.motion || !state.motion.clip || !(state.motion.clip instanceof AnimationClip)) {
|
341
341
|
// if(debug) console.warn("State has no clip or motion", state);
|
342
342
|
return;
|
343
343
|
}
|
@@ -503,8 +503,13 @@
|
|
503
503
|
|
504
504
|
if (state.motion?.clip) {
|
505
505
|
const clip = state.motion.clip;
|
506
|
-
|
507
|
-
|
506
|
+
if (clip instanceof AnimationClip) {
|
507
|
+
const action = this.createAction(clip);
|
508
|
+
state.motion.action = action;
|
509
|
+
}
|
510
|
+
else {
|
511
|
+
if(debug || isDevEnvironment()) console.warn("No valid animationclip assigned", state);
|
512
|
+
}
|
508
513
|
}
|
509
514
|
|
510
515
|
// create state machine behaviours
|
@@ -1,12 +1,23 @@
|
|
1
1
|
import { getParam } from "../engine/engine_utils";
|
2
2
|
const debug = getParam("debugdefines");
|
3
3
|
|
4
|
-
|
5
|
-
|
4
|
+
// We jump through hoops like this to support 3 cases:
|
5
|
+
// 1) Vanilla js or angular js where global defines are not guaranteed to be made
|
6
|
+
// 2) Vite where global defines are made, vite defines are also automatically set to globalThis
|
7
|
+
// 3) Webpack where global defines are not made BUT declare const variables are replaces with the actual value (via the webpack DefinePlugin)
|
6
8
|
|
7
9
|
tryEval(`if(!globalThis["NEEDLE_ENGINE_VERSION"]) globalThis["NEEDLE_ENGINE_VERSION"] = "0.0.0";`)
|
8
10
|
tryEval(`if(!globalThis["NEEDLE_ENGINE_GENERATOR"]) globalThis["NEEDLE_ENGINE_GENERATOR"] = "unknown";`)
|
9
11
|
|
12
|
+
declare const NEEDLE_ENGINE_VERSION: string
|
13
|
+
declare const NEEDLE_ENGINE_GENERATOR: string;
|
14
|
+
|
15
|
+
// Make sure to wrap the new global this define in underscores to prevent the bundler from replacing it with the actual value
|
16
|
+
tryEval(`globalThis["__NEEDLE_ENGINE_VERSION__"] = "` + NEEDLE_ENGINE_VERSION + `";`)
|
17
|
+
tryEval(`globalThis["__NEEDLE_ENGINE_GENERATOR__"] = "` + NEEDLE_ENGINE_GENERATOR + `";`)
|
18
|
+
|
19
|
+
|
20
|
+
|
10
21
|
export const VERSION = NEEDLE_ENGINE_VERSION;
|
11
22
|
export const GENERATOR = NEEDLE_ENGINE_GENERATOR;
|
12
23
|
if (debug) console.log(`Engine version: ${VERSION} (generator: ${GENERATOR})`);
|
@@ -26,8 +26,8 @@
|
|
26
26
|
/** Add to prevent Needle Engine context from being disposed when the element is removed from the DOM */
|
27
27
|
"keep-alive"? : boolean;
|
28
28
|
|
29
|
-
addEventListener(event: "ready", callback: (event: CustomEvent) => void): void;
|
30
|
-
addEventListener(event: "error", callback: (event: CustomEvent) => void): void;
|
29
|
+
addEventListener?(event: "ready", callback: (event: CustomEvent) => void): void;
|
30
|
+
addEventListener?(event: "error", callback: (event: CustomEvent) => void): void;
|
31
31
|
}
|
32
32
|
|
33
33
|
type LoadingAttributes = {
|
@@ -152,7 +152,7 @@
|
|
152
152
|
this.onSetupDesktop();
|
153
153
|
|
154
154
|
if (!this.getAttribute("src")) {
|
155
|
-
const global = globalThis["needle:codegen_files"];
|
155
|
+
const global = globalThis["needle:codegen_files"] as unknown as string;
|
156
156
|
if (global) {
|
157
157
|
if (debug) console.log("globalThis[\"needle:codegen_files\"]", global);
|
158
158
|
this.setAttribute("src", global);
|
@@ -89,18 +89,18 @@
|
|
89
89
|
await getLoader().createBuiltinComponents(context, gltfId, gltf, seed, componentsExtension);
|
90
90
|
}
|
91
91
|
|
92
|
-
export function createGLTFLoader(url: string, context: Context) {
|
92
|
+
export async function createGLTFLoader(url: string, context: Context) {
|
93
93
|
const loader = new GLTFLoader();
|
94
94
|
const sourceId: SourceIdentifier = url;
|
95
|
-
registerExtensions(loader, context, sourceId);
|
95
|
+
await registerExtensions(loader, context, sourceId);
|
96
96
|
return loader;
|
97
97
|
}
|
98
98
|
|
99
|
-
export function parseSync(context: Context, data: string | ArrayBuffer, path: string, seed: number | UIDProvider | null): Promise<GLTF | undefined> {
|
99
|
+
export async function parseSync(context: Context, data: string | ArrayBuffer, path: string, seed: number | UIDProvider | null): Promise<GLTF | undefined> {
|
100
100
|
if (typeof path !== "string") {
|
101
101
|
console.warn("Parse gltf binary without path, this might lead to errors in resolving extensions. Please provide the source path of the gltf/glb file", path, typeof path);
|
102
102
|
}
|
103
|
-
const loader = createGLTFLoader(path, context);
|
103
|
+
const loader = await createGLTFLoader(path, context);
|
104
104
|
const componentsExtension = registerComponentExtension(loader);
|
105
105
|
return new Promise((resolve, reject) => {
|
106
106
|
try {
|
@@ -125,13 +125,13 @@
|
|
125
125
|
});
|
126
126
|
}
|
127
127
|
|
128
|
-
export function loadSync(context: Context, url: string, sourceId: string, seed: number | UIDProvider | null, prog?: (ProgressEvent) => void): Promise<GLTF | undefined> {
|
128
|
+
export async function loadSync(context: Context, url: string, sourceId: string, seed: number | UIDProvider | null, prog?: (ProgressEvent) => void): Promise<GLTF | undefined> {
|
129
129
|
// better to create new loaders every time
|
130
130
|
// (maybe we can cache them...)
|
131
131
|
// but due to the async nature and potentially triggering multiple loads at the same time
|
132
132
|
// we need to make sure the extensions dont override each other
|
133
133
|
// creating new loaders should not be expensive as well
|
134
|
-
const loader = createGLTFLoader(url, context);
|
134
|
+
const loader = await createGLTFLoader(url, context);
|
135
135
|
const componentsExtension = registerComponentExtension(loader);
|
136
136
|
return new Promise((resolve, reject) => {
|
137
137
|
try {
|
@@ -18,9 +18,13 @@
|
|
18
18
|
else {
|
19
19
|
this.onBeforeRender();
|
20
20
|
const prev = renderer.getRenderTarget();
|
21
|
+
const xr = renderer.xr.enabled;
|
22
|
+
renderer.xr.enabled = false;
|
21
23
|
renderer.setRenderTarget(this);
|
24
|
+
renderer.clear(true, true, true);
|
22
25
|
renderer.render(scene, camera);
|
23
26
|
renderer.setRenderTarget(prev);
|
27
|
+
renderer.xr.enabled = xr;
|
24
28
|
this.onAfterRender();
|
25
29
|
}
|
26
30
|
}
|
@@ -16,11 +16,15 @@
|
|
16
16
|
import { InternalUsageTrackerPlugin } from "./usage_tracker";
|
17
17
|
import { isUsageTrackingEnabled } from "../engine_assetdatabase";
|
18
18
|
import { GLTFLoaderPlugin } from "three/examples/jsm/loaders/GLTFLoader.js";
|
19
|
+
import { getParam } from "../engine_utils";
|
20
|
+
import { isDevEnvironment } from "../debug";
|
19
21
|
// import { GLTFAnimationPointerExtension } from "three/examples/jsm/loaders/GLTFLoaderAnimationPointer";
|
20
22
|
|
23
|
+
const debug = getParam("debugextensions");
|
24
|
+
|
21
25
|
// lazily import the GLTFAnimationPointerExtension in case it doesnt exist (e.g. using vanilla three)
|
22
|
-
let GLTFAnimationPointerExtension
|
23
|
-
import("three/examples/jsm/loaders/GLTFLoaderAnimationPointer").then(mod => {
|
26
|
+
let GLTFAnimationPointerExtension: any;
|
27
|
+
const KHR_ANIMATIONPOINTER_IMPORT = import("three/examples/jsm/loaders/GLTFLoaderAnimationPointer.js").then(async mod => {
|
24
28
|
GLTFAnimationPointerExtension = mod.GLTFAnimationPointerExtension;
|
25
29
|
return GLTFAnimationPointerExtension;
|
26
30
|
}).catch(e => {
|
@@ -60,7 +64,7 @@
|
|
60
64
|
}
|
61
65
|
}
|
62
66
|
|
63
|
-
export function registerExtensions(loader: GLTFLoader, context: Context, sourceId: SourceIdentifier) {
|
67
|
+
export async function registerExtensions(loader: GLTFLoader, context: Context, sourceId: SourceIdentifier) {
|
64
68
|
|
65
69
|
// Make sure to remove any url parameters from the sourceId (because the source id in the renderer does not have a ?v=xxx so it will not be able to register the resolved lightmap otherwise)
|
66
70
|
const idEnd = sourceId.lastIndexOf("?");
|
@@ -80,6 +84,7 @@
|
|
80
84
|
for (const ext of _addedCustomExtension)
|
81
85
|
loader.register(p => new ext(p));
|
82
86
|
|
87
|
+
await KHR_ANIMATIONPOINTER_IMPORT.catch(_ => { })
|
83
88
|
loader.register(p => {
|
84
89
|
if (GLTFAnimationPointerExtension) {
|
85
90
|
const ext = new GLTFAnimationPointerExtension(p);
|
@@ -87,6 +92,12 @@
|
|
87
92
|
setPointerResolverFunction.bind(ext)(new PointerResolver());
|
88
93
|
return ext;
|
89
94
|
}
|
95
|
+
else {
|
96
|
+
if (debug || isDevEnvironment()) console.error("Missing KHR_animation_pointer extension...")
|
97
|
+
return {
|
98
|
+
name: "KHR_animation_pointer_NOT_AVAILABLE"
|
99
|
+
};
|
100
|
+
}
|
90
101
|
});
|
91
102
|
|
92
103
|
}
|
@@ -206,6 +206,7 @@
|
|
206
206
|
else {
|
207
207
|
this.setOptions({ backgroundImage: null, borderRadius: 0, backgroundOpacity: this.color.alpha });
|
208
208
|
}
|
209
|
+
this.markDirty();
|
209
210
|
}
|
210
211
|
|
211
212
|
protected onAfterAddedToScene(): void {
|
@@ -13,12 +13,8 @@
|
|
13
13
|
export class Image extends MaskableGraphic {
|
14
14
|
|
15
15
|
set image(img: Texture | null) {
|
16
|
-
if (this.sprite)
|
17
|
-
|
18
|
-
else {
|
19
|
-
this.sprite = new Sprite();
|
20
|
-
this.sprite.texture = img;
|
21
|
-
}
|
16
|
+
if (!this.sprite) this.sprite = new Sprite();
|
17
|
+
this.sprite.texture = img;
|
22
18
|
this.onAfterCreated();
|
23
19
|
}
|
24
20
|
get image(): Texture | null {
|
@@ -72,8 +68,9 @@
|
|
72
68
|
}
|
73
69
|
|
74
70
|
protected onAfterCreated(): void {
|
75
|
-
if(!this.__didAwake) return;
|
71
|
+
if (!this.__didAwake) return;
|
76
72
|
super.onAfterCreated();
|
73
|
+
// TODO: @swingingtom setting a built-in sprite at runtime doesnt update the image
|
77
74
|
if (this.isBuiltinSprite()) return;
|
78
75
|
this.setTexture(this.sprite?.texture);
|
79
76
|
}
|
@@ -112,7 +112,6 @@
|
|
112
112
|
// TODO: get rid of the initial position
|
113
113
|
this._initialPosition = this.gameObject.position.clone();
|
114
114
|
this._initialPosition.z = 0;
|
115
|
-
this.onApplyTransform("RectTransform awake");
|
116
115
|
|
117
116
|
// TODO: we need to replace this with the watch that e.g. Rigibody is using (or the one in utils?)
|
118
117
|
// perhaps we can also just manually check the few properties in the update loops?
|
@@ -129,6 +128,7 @@
|
|
129
128
|
this.addShadowComponent(this.rectBlock);
|
130
129
|
this._transformNeedsUpdate = true;
|
131
130
|
this.Canvas?.registerTransform(this);
|
131
|
+
// this.onApplyTransform("enable");
|
132
132
|
}
|
133
133
|
|
134
134
|
onDisable() {
|
@@ -104,8 +104,7 @@
|
|
104
104
|
|
105
105
|
onBeforeRender(): void {
|
106
106
|
// TODO TMUI @swingingtom this is so we don't have text clipping
|
107
|
-
if (this.uiObject && (this.Canvas?.screenspace || this.context.isInVR))
|
108
|
-
{
|
107
|
+
if (this.uiObject && (this.Canvas?.screenspace || this.context.isInVR)) {
|
109
108
|
this.updateOverflow();
|
110
109
|
}
|
111
110
|
}
|
@@ -269,11 +268,12 @@
|
|
269
268
|
return opts;
|
270
269
|
}
|
271
270
|
|
272
|
-
private feedText(text: string, richText: boolean) {
|
271
|
+
private feedText(text: string, richText: boolean) : void {
|
273
272
|
// if (!text || text.length <= 0) return;
|
274
273
|
// if (!text ) return;
|
274
|
+
if (debug) console.log("feedText", this.uiObject, text, richText);
|
275
275
|
|
276
|
-
if (!this.uiObject) return
|
276
|
+
if (!this.uiObject) return;
|
277
277
|
if (!this._textMeshUi)
|
278
278
|
this._textMeshUi = [];
|
279
279
|
|
@@ -291,29 +291,25 @@
|
|
291
291
|
} else {
|
292
292
|
let currentTag = this.getNextTag(text);
|
293
293
|
if (!currentTag) {
|
294
|
-
//@TODO: @swingingtom how would the text content be set?
|
295
294
|
//@ts-ignore
|
296
|
-
|
295
|
+
// we have to set it to empty string, otherwise TMUI won't update it @swingingtom
|
296
|
+
this.uiObject.textContent = ""; // <
|
297
|
+
this.setOptions({ textContent: text });
|
298
|
+
return;
|
297
299
|
} else if (currentTag.startIndex > 0) {
|
298
|
-
|
299
300
|
// First segment should also clear children inlines
|
300
|
-
for (
|
301
|
-
const child = this.uiObject.children[
|
302
|
-
|
301
|
+
for (let i = this.uiObject.children.length - 1; i >= 0; i--) {
|
302
|
+
const child = this.uiObject.children[i];
|
303
303
|
// @ts-ignore
|
304
|
-
if(
|
305
|
-
|
306
|
-
this.uiObject.remove( child );
|
304
|
+
if (child.isUI) {
|
305
|
+
this.uiObject.remove(child);
|
307
306
|
child.clear();
|
308
|
-
|
309
307
|
}
|
310
|
-
|
311
308
|
}
|
312
|
-
|
313
|
-
|
314
309
|
const el = new ThreeMeshUI.Inline({ textContent: text.substring(0, currentTag.startIndex), color: 'inherit' });
|
315
310
|
this.uiObject.add(el);
|
316
311
|
}
|
312
|
+
|
317
313
|
const stackArray: Array<TagStackEntry> = [];
|
318
314
|
while (currentTag) {
|
319
315
|
const next = this.getNextTag(text, currentTag.endIndex);
|
@@ -325,17 +321,13 @@
|
|
325
321
|
}
|
326
322
|
|
327
323
|
if (next) {
|
328
|
-
|
329
324
|
opts.textContent = this.getText(text, currentTag, next);
|
330
|
-
|
331
325
|
this.handleTag(currentTag, opts, stackArray);
|
332
326
|
const el = new ThreeMeshUI.Inline(opts);
|
333
327
|
this.uiObject?.add(el)
|
334
328
|
|
335
329
|
} else {
|
336
|
-
|
337
330
|
opts.textContent = text.substring(currentTag.endIndex);
|
338
|
-
|
339
331
|
this.handleTag(currentTag, opts, stackArray);
|
340
332
|
const el = new ThreeMeshUI.Inline(opts);
|
341
333
|
this.uiObject?.add(el);
|
@@ -343,10 +335,6 @@
|
|
343
335
|
currentTag = next;
|
344
336
|
}
|
345
337
|
}
|
346
|
-
|
347
|
-
if(debug) console.log("feedText", this.uiObject);
|
348
|
-
|
349
|
-
return null;
|
350
338
|
}
|
351
339
|
|
352
340
|
private _didHandleTextRenderOnTop: boolean = false;
|
@@ -514,7 +502,7 @@
|
|
514
502
|
// e.g. -Medium, -Black, -Thin...
|
515
503
|
const styleName = familyName.substring(styleSeparator + 1)?.toLowerCase();
|
516
504
|
if (unsupportedStyleNames.includes(styleName)) {
|
517
|
-
if(debug) console.warn("Unsupported font style: " + styleName);
|
505
|
+
if (debug) console.warn("Unsupported font style: " + styleName);
|
518
506
|
return familyName;
|
519
507
|
}
|
520
508
|
|
@@ -11,7 +11,7 @@
|
|
11
11
|
ShaderLib,
|
12
12
|
ShaderMaterial,
|
13
13
|
DoubleSide,
|
14
|
-
PerspectiveCamera
|
14
|
+
PerspectiveCamera,
|
15
15
|
} from "three";
|
16
16
|
|
17
17
|
export class WebARCameraBackground extends Behaviour {
|
@@ -74,7 +74,6 @@
|
|
74
74
|
// from https://stackoverflow.com/a/55084367 to inject a custom texture into three.js
|
75
75
|
if (!this.threeTexture && this.context.renderer) {
|
76
76
|
this.threeTexture = new Texture();
|
77
|
-
// this.threeTexture.encoding = LinearEncoding;
|
78
77
|
this.forceTextureInitialization(this.context.renderer, this.threeTexture);
|
79
78
|
}
|
80
79
|
|
@@ -132,6 +131,17 @@
|
|
132
131
|
this.backgroundPlane.setTexture(this.threeTexture);
|
133
132
|
this.backgroundPlane.visible = true;
|
134
133
|
}
|
134
|
+
|
135
|
+
// TODO this would be a lot better but currently
|
136
|
+
// setting color space doesn't work.
|
137
|
+
// Plus we need to understand how we can supply a custom shader in
|
138
|
+
// this case.
|
139
|
+
/*
|
140
|
+
if (this.threeTexture) {
|
141
|
+
this.context.scene.background = this.threeTexture;
|
142
|
+
this.threeTexture.colorSpace = NoColorSpace;
|
143
|
+
}
|
144
|
+
*/
|
135
145
|
}
|
136
146
|
}
|
137
147
|
else {
|
@@ -0,0 +1,20 @@
|
|
1
|
+
import { existsSync, readFileSync } from "fs";
|
2
|
+
|
3
|
+
export function getMeta() {
|
4
|
+
const workingDirectory = process.cwd();
|
5
|
+
const configPath = workingDirectory + "/needle.config.json";
|
6
|
+
if(existsSync(configPath)) {
|
7
|
+
const configStr = readFileSync(configPath);
|
8
|
+
const config = JSON.parse(configStr);
|
9
|
+
if(config.codegenDirectory) {
|
10
|
+
const dir = workingDirectory + "/" + config.codegenDirectory + "/meta.json";
|
11
|
+
if(existsSync(dir)) {
|
12
|
+
const metaStr = readFileSync(dir);
|
13
|
+
/**@type {import("../types").needleConfig} */
|
14
|
+
const meta = JSON.parse(metaStr);
|
15
|
+
return meta;
|
16
|
+
}
|
17
|
+
}
|
18
|
+
}
|
19
|
+
return null;
|
20
|
+
}
|
@@ -0,0 +1,11 @@
|
|
1
|
+
import { getMeta } from "./config.js";
|
2
|
+
|
3
|
+
|
4
|
+
/** @returns {string|null} */
|
5
|
+
export function tryGetGenerator() {
|
6
|
+
const meta = getMeta();
|
7
|
+
if (meta) {
|
8
|
+
return meta.generator;
|
9
|
+
}
|
10
|
+
return null;
|
11
|
+
}
|
@@ -0,0 +1,12 @@
|
|
1
|
+
import { existsSync, readFileSync } from "fs";
|
2
|
+
|
3
|
+
/** @returns {string|null} */
|
4
|
+
export function tryGetNeedleEngineVersion() {
|
5
|
+
const needleEnginePackageJsonPath = process.cwd() + "/node_modules/@needle-tools/engine/package.json";
|
6
|
+
if (existsSync(needleEnginePackageJsonPath)) {
|
7
|
+
const json = JSON.parse(readFileSync(needleEnginePackageJsonPath));
|
8
|
+
const version = json.version;
|
9
|
+
return version;
|
10
|
+
}
|
11
|
+
return null;
|
12
|
+
}
|