@decohere/workspace 0.0.1-dev.116
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +81 -0
- package/commonjs/src/const.js +69 -0
- package/commonjs/src/errors.js +12 -0
- package/commonjs/src/factories/config.factory.js +90 -0
- package/commonjs/src/factories/find-workspace-root.js +37 -0
- package/commonjs/src/factories/project.factory.js +72 -0
- package/commonjs/src/factories/workspace.factory.js +50 -0
- package/commonjs/src/index.js +74 -0
- package/commonjs/src/models/has-package-json.mixin.js +50 -0
- package/commonjs/src/models/has-tsconfig.mixin.js +75 -0
- package/commonjs/src/models/package-aliases.js +112 -0
- package/commonjs/src/models/package-json.model.js +196 -0
- package/commonjs/src/models/project-file-event.js +4 -0
- package/commonjs/src/models/project.model.js +316 -0
- package/commonjs/src/models/source-extensions.js +81 -0
- package/commonjs/src/models/tsconfig.model.js +97 -0
- package/commonjs/src/models/workspace-config.type.js +7 -0
- package/commonjs/src/models/workspace.model.js +153 -0
- package/es6/src/const.js +36 -0
- package/es6/src/errors.js +2 -0
- package/es6/src/factories/config.factory.js +34 -0
- package/es6/src/factories/find-workspace-root.js +26 -0
- package/es6/src/factories/project.factory.js +57 -0
- package/es6/src/factories/workspace.factory.js +35 -0
- package/es6/src/index.js +14 -0
- package/es6/src/models/has-package-json.mixin.js +35 -0
- package/es6/src/models/has-tsconfig.mixin.js +60 -0
- package/es6/src/models/package-aliases.js +97 -0
- package/es6/src/models/package-json.model.js +186 -0
- package/es6/src/models/project-file-event.js +1 -0
- package/es6/src/models/project.model.js +301 -0
- package/es6/src/models/source-extensions.js +66 -0
- package/es6/src/models/tsconfig.model.js +74 -0
- package/es6/src/models/workspace-config.type.js +4 -0
- package/es6/src/models/workspace.model.js +143 -0
- package/package.json +34 -0
- package/types/src/const.d.ts +8 -0
- package/types/src/errors.d.ts +2 -0
- package/types/src/factories/config.factory.d.ts +6 -0
- package/types/src/factories/find-workspace-root.d.ts +6 -0
- package/types/src/factories/project.factory.d.ts +8 -0
- package/types/src/factories/workspace.factory.d.ts +9 -0
- package/types/src/index.d.ts +18 -0
- package/types/src/models/has-package-json.mixin.d.ts +9 -0
- package/types/src/models/has-tsconfig.mixin.d.ts +11 -0
- package/types/src/models/package-aliases.d.ts +28 -0
- package/types/src/models/package-json.model.d.ts +39 -0
- package/types/src/models/project-file-event.d.ts +8 -0
- package/types/src/models/project.model.d.ts +64 -0
- package/types/src/models/source-extensions.d.ts +22 -0
- package/types/src/models/tsconfig.model.d.ts +11 -0
- package/types/src/models/workspace-config.type.d.ts +52 -0
- package/types/src/models/workspace.model.d.ts +40 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "packageAliases", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return packageAliases;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _nodefs = require("node:fs");
|
|
12
|
+
const _nodepath = /*#__PURE__*/ _interop_require_default(require("node:path"));
|
|
13
|
+
const _sourceextensions = require("./source-extensions.js");
|
|
14
|
+
function _interop_require_default(obj) {
|
|
15
|
+
return obj && obj.__esModule ? obj : {
|
|
16
|
+
default: obj
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Convention aliases from workspace packages, then tsconfig `paths` for the same keys.
|
|
21
|
+
* Prefer `Workspace.getPackageAliases` when a workspace is available.
|
|
22
|
+
*/ function build(projects, options) {
|
|
23
|
+
const baseUrl = _nodepath.default.resolve(options.baseUrl);
|
|
24
|
+
const paths = {
|
|
25
|
+
...conventionAliasPaths(projects, baseUrl),
|
|
26
|
+
...options.tsconfigPaths
|
|
27
|
+
};
|
|
28
|
+
return {
|
|
29
|
+
baseUrl,
|
|
30
|
+
paths
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/** Bare import specifier that is not relative, absolute, or a node/file URL. */ function isBareSpecifier(specifier) {
|
|
34
|
+
return specifier.length > 0 && !specifier.startsWith(".") && !specifier.startsWith("/") && !specifier.startsWith("node:") && !specifier.startsWith("file:") && !specifier.startsWith("data:") && !specifier.startsWith("#");
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Resolve a bare specifier through package aliases (SWC-style `paths`
|
|
38
|
+
* relative to `baseUrl`) to an absolute `.ts` path. Longest key wins.
|
|
39
|
+
*/ function resolvePath(specifier, paths, baseUrl) {
|
|
40
|
+
if (!isBareSpecifier(specifier)) return null;
|
|
41
|
+
const resolvedBase = _nodepath.default.resolve(baseUrl);
|
|
42
|
+
const keys = Object.keys(paths).sort((a, b)=>b.length - a.length);
|
|
43
|
+
for (const key of keys){
|
|
44
|
+
const target = paths[key]?.[0];
|
|
45
|
+
if (target == null) continue;
|
|
46
|
+
if (key.endsWith("/*")) {
|
|
47
|
+
const prefix = key.slice(0, -1);
|
|
48
|
+
if (!specifier.startsWith(prefix)) continue;
|
|
49
|
+
const mappedRoot = target.endsWith("/*") ? target.slice(0, -2) : target;
|
|
50
|
+
const subpath = specifier.slice(prefix.length);
|
|
51
|
+
return subpathSource(_nodepath.default.resolve(resolvedBase, mappedRoot, subpath));
|
|
52
|
+
}
|
|
53
|
+
if (specifier === key) {
|
|
54
|
+
return toTsSourcePath(_nodepath.default.resolve(resolvedBase, target.replace(/\*$/, "")));
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
function conventionAliasPaths(projects, baseUrl) {
|
|
60
|
+
const aliases = {};
|
|
61
|
+
for (const project of projects){
|
|
62
|
+
const name = project.name;
|
|
63
|
+
if (name.length === 0) continue;
|
|
64
|
+
const entry = _nodepath.default.resolve(project.getSourceEntryPath());
|
|
65
|
+
// A package with no root entry (only subpaths, like core) gets no bare alias, and its
|
|
66
|
+
// subpaths resolve under `src/`.
|
|
67
|
+
const hasEntry = (0, _nodefs.existsSync)(entry);
|
|
68
|
+
if (hasEntry) aliases[name] = [
|
|
69
|
+
toPosixRelative(baseUrl, entry)
|
|
70
|
+
];
|
|
71
|
+
const subpathRoot = hasEntry ? _nodepath.default.dirname(entry) : _nodepath.default.resolve(project.rootDir, project.projectDirectory, "src");
|
|
72
|
+
if ((0, _nodefs.existsSync)(subpathRoot)) {
|
|
73
|
+
aliases[`${name}/*`] = [
|
|
74
|
+
`${toPosixRelative(baseUrl, subpathRoot)}/*`
|
|
75
|
+
];
|
|
76
|
+
}
|
|
77
|
+
// Subpaths the package exports, mapped to their sources (#518): these can name any file,
|
|
78
|
+
// not just `<sub>.ts` or `<sub>/index.ts` under the entry's directory.
|
|
79
|
+
for (const [subpath, source] of Object.entries(project.getSourceExports())){
|
|
80
|
+
aliases[`${name}/${subpath.slice(2)}`] = [
|
|
81
|
+
toPosixRelative(baseUrl, source)
|
|
82
|
+
];
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return aliases;
|
|
86
|
+
}
|
|
87
|
+
function toPosixRelative(from, to) {
|
|
88
|
+
const relative = _nodepath.default.relative(from, to);
|
|
89
|
+
if (relative === "") return ".";
|
|
90
|
+
return relative.split(_nodepath.default.sep).join("/");
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* The source file a wildcard subpath names: `<sub>` with a source extension (`.ts`, `.tsx`, or
|
|
94
|
+
* `.mts`/`.cts` for `.mjs`/`.cjs`), else the `index` source of the directory it names (as
|
|
95
|
+
* `@pkg/models` is `src/models/index.ts`), else `<sub>.ts` for the caller to report missing.
|
|
96
|
+
*/ function subpathSource(candidate) {
|
|
97
|
+
const files = _sourceextensions.sourceExtensions.candidates(candidate);
|
|
98
|
+
const directory = candidate.replace(/\.([mc]?[jt]sx?)$/, "");
|
|
99
|
+
const indexes = _sourceextensions.sourceExtensions.candidates(_nodepath.default.join(directory, "index"));
|
|
100
|
+
return [
|
|
101
|
+
...files,
|
|
102
|
+
...indexes
|
|
103
|
+
].find((file)=>(0, _nodefs.existsSync)(file)) ?? toTsSourcePath(candidate);
|
|
104
|
+
}
|
|
105
|
+
/** A target as a source path: itself when it is one, else its first source candidate. */ function toTsSourcePath(candidate) {
|
|
106
|
+
return _sourceextensions.sourceExtensions.candidates(candidate)[0] ?? `${candidate}.ts`;
|
|
107
|
+
}
|
|
108
|
+
const packageAliases = {
|
|
109
|
+
build,
|
|
110
|
+
isBareSpecifier,
|
|
111
|
+
resolvePath
|
|
112
|
+
};
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "PackageJson", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return PackageJson;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
class PackageJson {
|
|
12
|
+
static PACKAGE_JSON_KEY_ORDER = [
|
|
13
|
+
"$schema",
|
|
14
|
+
"name",
|
|
15
|
+
"displayName",
|
|
16
|
+
"version",
|
|
17
|
+
"description",
|
|
18
|
+
"keywords",
|
|
19
|
+
"homepage",
|
|
20
|
+
"bugs",
|
|
21
|
+
"repository",
|
|
22
|
+
"license",
|
|
23
|
+
"author",
|
|
24
|
+
"contributors",
|
|
25
|
+
"funding",
|
|
26
|
+
"type",
|
|
27
|
+
"main",
|
|
28
|
+
"module",
|
|
29
|
+
"types",
|
|
30
|
+
"exports",
|
|
31
|
+
"files",
|
|
32
|
+
"bin",
|
|
33
|
+
"man",
|
|
34
|
+
"directories",
|
|
35
|
+
"scripts",
|
|
36
|
+
"dependencies",
|
|
37
|
+
"devDependencies",
|
|
38
|
+
"peerDependencies",
|
|
39
|
+
"peerDependenciesMeta",
|
|
40
|
+
"optionalDependencies",
|
|
41
|
+
"bundledDependencies",
|
|
42
|
+
"engines",
|
|
43
|
+
"os",
|
|
44
|
+
"cpu",
|
|
45
|
+
"private",
|
|
46
|
+
"publishConfig",
|
|
47
|
+
"workspaces",
|
|
48
|
+
"packageManager",
|
|
49
|
+
"forge"
|
|
50
|
+
];
|
|
51
|
+
constructor(data){
|
|
52
|
+
Object.assign(this, data);
|
|
53
|
+
this.dependencies = this.dependencies ?? {};
|
|
54
|
+
this.devDependencies = this.devDependencies ?? {};
|
|
55
|
+
}
|
|
56
|
+
sort() {
|
|
57
|
+
const sorted = this.toSortedPackageJsonRecord();
|
|
58
|
+
Object.assign(this, sorted);
|
|
59
|
+
return this;
|
|
60
|
+
}
|
|
61
|
+
withVersion(version) {
|
|
62
|
+
return new PackageJson({
|
|
63
|
+
...this,
|
|
64
|
+
version
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
withDependencies(dependencies) {
|
|
68
|
+
return new PackageJson({
|
|
69
|
+
...this,
|
|
70
|
+
dependencies
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
withDevDependencies(devDependencies) {
|
|
74
|
+
return new PackageJson({
|
|
75
|
+
...this,
|
|
76
|
+
devDependencies
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
toJSON() {
|
|
80
|
+
return `${JSON.stringify(this.toSortedPackageJsonRecord(), null, 2)}\n`;
|
|
81
|
+
}
|
|
82
|
+
getRepositoryOwner() {
|
|
83
|
+
return this.parseRepository()?.owner;
|
|
84
|
+
}
|
|
85
|
+
getRepositoryName() {
|
|
86
|
+
return this.parseRepository()?.name;
|
|
87
|
+
}
|
|
88
|
+
getRepositoryFullName() {
|
|
89
|
+
const parsed = this.parseRepository();
|
|
90
|
+
if (parsed == null) {
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
93
|
+
return `${parsed.owner}/${parsed.name}`;
|
|
94
|
+
}
|
|
95
|
+
sortDependencyMap(input) {
|
|
96
|
+
return Object.fromEntries(Object.entries(input).sort(([left], [right])=>left.localeCompare(right, "en")));
|
|
97
|
+
}
|
|
98
|
+
sortPackageJsonKeys(source) {
|
|
99
|
+
const sorted = Object.create(null);
|
|
100
|
+
for (const key of PackageJson.PACKAGE_JSON_KEY_ORDER){
|
|
101
|
+
if (key in source) {
|
|
102
|
+
sorted[key] = source[key];
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
const remainingKeys = Object.keys(source).filter((key)=>!PackageJson.PACKAGE_JSON_KEY_ORDER.includes(key)).sort();
|
|
106
|
+
for (const key of remainingKeys){
|
|
107
|
+
sorted[key] = source[key];
|
|
108
|
+
}
|
|
109
|
+
return sorted;
|
|
110
|
+
}
|
|
111
|
+
toSortedPackageJsonRecord() {
|
|
112
|
+
const clone = {
|
|
113
|
+
...this
|
|
114
|
+
};
|
|
115
|
+
if (clone.dependencies) {
|
|
116
|
+
clone.dependencies = this.sortDependencyMap(clone.dependencies);
|
|
117
|
+
}
|
|
118
|
+
if (clone.devDependencies) {
|
|
119
|
+
clone.devDependencies = this.sortDependencyMap(clone.devDependencies);
|
|
120
|
+
}
|
|
121
|
+
return this.sortPackageJsonKeys(clone);
|
|
122
|
+
}
|
|
123
|
+
repositoryReferenceToString(repository) {
|
|
124
|
+
if (typeof repository === "string") {
|
|
125
|
+
return repository;
|
|
126
|
+
}
|
|
127
|
+
if (repository == null) {
|
|
128
|
+
return "";
|
|
129
|
+
}
|
|
130
|
+
return String(repository.url ?? "");
|
|
131
|
+
}
|
|
132
|
+
parseRepository() {
|
|
133
|
+
const repositoryValue = this.repositoryReferenceToString(this.repository);
|
|
134
|
+
if (repositoryValue === "") {
|
|
135
|
+
return undefined;
|
|
136
|
+
}
|
|
137
|
+
const trimmed = repositoryValue.trim();
|
|
138
|
+
if (!trimmed.includes("://") && !trimmed.startsWith("git@")) {
|
|
139
|
+
const shorthand = /^(?:[a-z0-9-]+:)?([^/\s]+)\/([^\s]+)$/i.exec(trimmed);
|
|
140
|
+
if (shorthand) {
|
|
141
|
+
return {
|
|
142
|
+
owner: shorthand[1].toLowerCase(),
|
|
143
|
+
name: this.sanitizeRepositoryName(shorthand[2])
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
const ssh = /^git@[^:]+:([^/\s]+)\/([^\s]+)$/i.exec(trimmed);
|
|
148
|
+
if (ssh) {
|
|
149
|
+
return {
|
|
150
|
+
owner: ssh[1].toLowerCase(),
|
|
151
|
+
name: this.sanitizeRepositoryName(ssh[2])
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
const urlRepository = this.parseRepositoryFromUrl(trimmed);
|
|
155
|
+
if (urlRepository != null) {
|
|
156
|
+
return urlRepository;
|
|
157
|
+
}
|
|
158
|
+
return undefined;
|
|
159
|
+
}
|
|
160
|
+
parseRepositoryFromUrl(repository) {
|
|
161
|
+
const normalized = repository.replace(/^git\+/, "");
|
|
162
|
+
let url;
|
|
163
|
+
try {
|
|
164
|
+
url = new URL(normalized);
|
|
165
|
+
} catch {
|
|
166
|
+
return undefined;
|
|
167
|
+
}
|
|
168
|
+
const segments = url.pathname.split("/").filter(Boolean);
|
|
169
|
+
if (segments.length < 2) {
|
|
170
|
+
return undefined;
|
|
171
|
+
}
|
|
172
|
+
const owner = segments[0]?.toLowerCase();
|
|
173
|
+
const name = this.sanitizeRepositoryName(segments[1] ?? "");
|
|
174
|
+
if (owner == null || owner === "" || name === "") {
|
|
175
|
+
return undefined;
|
|
176
|
+
}
|
|
177
|
+
return {
|
|
178
|
+
owner,
|
|
179
|
+
name
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
sanitizeRepositoryName(name) {
|
|
183
|
+
return name.replace(/\.git$/i, "").toLowerCase();
|
|
184
|
+
}
|
|
185
|
+
name;
|
|
186
|
+
version;
|
|
187
|
+
repository;
|
|
188
|
+
main;
|
|
189
|
+
/** `exports` as written in package.json: a path, or a map of subpaths (values may be condition maps). */ exports;
|
|
190
|
+
peerDependencies;
|
|
191
|
+
optionalDependencies;
|
|
192
|
+
scripts;
|
|
193
|
+
dependencies = {};
|
|
194
|
+
devDependencies = {};
|
|
195
|
+
private;
|
|
196
|
+
}
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "Project", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return Project;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _nodefs = require("node:fs");
|
|
12
|
+
const _nodepath = /*#__PURE__*/ _interop_require_default(require("node:path"));
|
|
13
|
+
const _caching = require("@decohere/core/caching");
|
|
14
|
+
const _extensibility = require("@decohere/core/extensibility");
|
|
15
|
+
const _io = require("@decohere/core/io");
|
|
16
|
+
const _picomatch = /*#__PURE__*/ _interop_require_default(require("picomatch"));
|
|
17
|
+
const _rxjs = require("rxjs");
|
|
18
|
+
const _errors = require("../errors.js");
|
|
19
|
+
const _haspackagejsonmixin = require("./has-package-json.mixin.js");
|
|
20
|
+
const _hastsconfigmixin = require("./has-tsconfig.mixin.js");
|
|
21
|
+
const _packagejsonmodel = require("./package-json.model.js");
|
|
22
|
+
const _sourceextensions = require("./source-extensions.js");
|
|
23
|
+
function _interop_require_default(obj) {
|
|
24
|
+
return obj && obj.__esModule ? obj : {
|
|
25
|
+
default: obj
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function _ts_decorate(decorators, target, key, desc) {
|
|
29
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
30
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
31
|
+
else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
32
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
33
|
+
}
|
|
34
|
+
function _ts_metadata(k, v) {
|
|
35
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
36
|
+
}
|
|
37
|
+
class Project extends (0, _extensibility.mixwith)(_haspackagejsonmixin.HasPackageJson, _hastsconfigmixin.HasTsConfig) {
|
|
38
|
+
packageJson;
|
|
39
|
+
#projectFileChangedSubject = new _rxjs.Subject();
|
|
40
|
+
#sourceFiles = new Map();
|
|
41
|
+
#projectConfig;
|
|
42
|
+
#name;
|
|
43
|
+
#projectDirectory;
|
|
44
|
+
#selectedConfiguration;
|
|
45
|
+
#hasLoadedSourceFiles = false;
|
|
46
|
+
#watcher;
|
|
47
|
+
constructor(name, config = {}, selectedConfigurationName){
|
|
48
|
+
super();
|
|
49
|
+
this.#name = name;
|
|
50
|
+
this.#projectDirectory = config?.projectDir ?? name;
|
|
51
|
+
this.#projectConfig = config;
|
|
52
|
+
this.#selectedConfiguration = this.resolveConfiguration(selectedConfigurationName);
|
|
53
|
+
this.packageJson = config.packageJson ?? new _packagejsonmodel.PackageJson();
|
|
54
|
+
}
|
|
55
|
+
get name() {
|
|
56
|
+
return this.#name;
|
|
57
|
+
}
|
|
58
|
+
get isPrivate() {
|
|
59
|
+
return this.packageJson?.private === true;
|
|
60
|
+
}
|
|
61
|
+
toString() {
|
|
62
|
+
return `Project(${this.#name})`;
|
|
63
|
+
}
|
|
64
|
+
get projectDirectory() {
|
|
65
|
+
return this.#projectDirectory;
|
|
66
|
+
}
|
|
67
|
+
get projectRoot() {
|
|
68
|
+
return _nodepath.default.resolve(this.#projectConfig.rootDir ?? "./", this.#projectDirectory);
|
|
69
|
+
}
|
|
70
|
+
get configuration() {
|
|
71
|
+
return this.#selectedConfiguration;
|
|
72
|
+
}
|
|
73
|
+
get packageJsonDirectory() {
|
|
74
|
+
return this.#absoluteProjectDir;
|
|
75
|
+
}
|
|
76
|
+
get tsConfigDirectory() {
|
|
77
|
+
return this.#absoluteProjectDir;
|
|
78
|
+
}
|
|
79
|
+
get fallbackTsConfigDirectory() {
|
|
80
|
+
return this.#projectConfig.rootDir;
|
|
81
|
+
}
|
|
82
|
+
get rootDir() {
|
|
83
|
+
return this.#projectConfig.rootDir ?? "./";
|
|
84
|
+
}
|
|
85
|
+
get #absoluteProjectDir() {
|
|
86
|
+
return this.projectRoot;
|
|
87
|
+
}
|
|
88
|
+
get include() {
|
|
89
|
+
return this.#selectedConfiguration.include ?? this.#projectConfig.include ?? [];
|
|
90
|
+
}
|
|
91
|
+
get ignore() {
|
|
92
|
+
const baseIgnore = this.#projectConfig.ignore ?? [];
|
|
93
|
+
const selectedIgnore = this.#selectedConfiguration.ignore ?? [];
|
|
94
|
+
return [
|
|
95
|
+
...baseIgnore,
|
|
96
|
+
...selectedIgnore
|
|
97
|
+
];
|
|
98
|
+
}
|
|
99
|
+
get copyFiles() {
|
|
100
|
+
const base = this.#projectConfig.copyFiles ?? [];
|
|
101
|
+
const selected = this.#selectedConfiguration.copyFiles ?? [];
|
|
102
|
+
return [
|
|
103
|
+
...base,
|
|
104
|
+
...selected
|
|
105
|
+
];
|
|
106
|
+
}
|
|
107
|
+
get dockerConfig() {
|
|
108
|
+
return this.#projectConfig.docker;
|
|
109
|
+
}
|
|
110
|
+
get uiConfig() {
|
|
111
|
+
return this.#projectConfig.ui;
|
|
112
|
+
}
|
|
113
|
+
get configurations() {
|
|
114
|
+
return this.#projectConfig.configurations ?? [];
|
|
115
|
+
}
|
|
116
|
+
get projectFileChanged$() {
|
|
117
|
+
return this.#projectFileChangedSubject.asObservable();
|
|
118
|
+
}
|
|
119
|
+
async getAllFiles() {
|
|
120
|
+
const files = await _io.io.findFiles(this.include, {
|
|
121
|
+
cwd: this.#absoluteProjectDir,
|
|
122
|
+
ignore: this.ignore
|
|
123
|
+
});
|
|
124
|
+
this.#sourceFiles.clear();
|
|
125
|
+
for (const file of files){
|
|
126
|
+
this.#sourceFiles.set(file.relativePath, file);
|
|
127
|
+
}
|
|
128
|
+
this.#hasLoadedSourceFiles = true;
|
|
129
|
+
return files;
|
|
130
|
+
}
|
|
131
|
+
isSourceFile(file) {
|
|
132
|
+
return this.#sourceFiles.has(file.relativePath);
|
|
133
|
+
}
|
|
134
|
+
async watch(configuration) {
|
|
135
|
+
if (this.#watcher != null) {
|
|
136
|
+
return this.#watcher;
|
|
137
|
+
}
|
|
138
|
+
if (!this.#hasLoadedSourceFiles) {
|
|
139
|
+
await this.getAllFiles();
|
|
140
|
+
}
|
|
141
|
+
const watcher = _io.io.watch(this.#absoluteProjectDir, {
|
|
142
|
+
ignoreInitial: true
|
|
143
|
+
});
|
|
144
|
+
this.#watcher = watcher;
|
|
145
|
+
watcher.on(_io.io.WatchEvents.add, (file)=>{
|
|
146
|
+
const fileEx = file;
|
|
147
|
+
this.updateSourceFileCache(_io.io.WatchEvents.add, fileEx);
|
|
148
|
+
this.#projectFileChangedSubject.next({
|
|
149
|
+
project: this,
|
|
150
|
+
configuration,
|
|
151
|
+
eventName: _io.io.WatchEvents.add,
|
|
152
|
+
file: fileEx
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
watcher.on(_io.io.WatchEvents.change, (file)=>{
|
|
156
|
+
const fileEx = file;
|
|
157
|
+
this.updateSourceFileCache(_io.io.WatchEvents.change, fileEx);
|
|
158
|
+
this.#projectFileChangedSubject.next({
|
|
159
|
+
project: this,
|
|
160
|
+
configuration,
|
|
161
|
+
eventName: _io.io.WatchEvents.change,
|
|
162
|
+
file: fileEx
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
watcher.on(_io.io.WatchEvents.unlink, (file)=>{
|
|
166
|
+
const fileEx = file;
|
|
167
|
+
this.updateSourceFileCache(_io.io.WatchEvents.unlink, fileEx);
|
|
168
|
+
this.#projectFileChangedSubject.next({
|
|
169
|
+
project: this,
|
|
170
|
+
configuration,
|
|
171
|
+
eventName: _io.io.WatchEvents.unlink,
|
|
172
|
+
file: fileEx
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
return watcher;
|
|
176
|
+
}
|
|
177
|
+
stopWatching() {
|
|
178
|
+
this.#watcher?.close();
|
|
179
|
+
this.#watcher = undefined;
|
|
180
|
+
}
|
|
181
|
+
getRootOut() {
|
|
182
|
+
return _nodepath.default.join(this.getWorkspaceOut(), this.#selectedConfiguration.name);
|
|
183
|
+
}
|
|
184
|
+
getOutDir(target = "") {
|
|
185
|
+
const targetDir = this.#selectedConfiguration.pack ? _nodepath.default.join(this.projectDirectory, target) : _nodepath.default.join(this.projectDirectory);
|
|
186
|
+
const out = _nodepath.default.join(this.getRootOut(), targetDir);
|
|
187
|
+
return out;
|
|
188
|
+
}
|
|
189
|
+
getConfiguration(name) {
|
|
190
|
+
return this.configurations.find((b)=>b.name === name);
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* The package's entry source file. A TypeScript `main` (the workspace convention,
|
|
194
|
+
* `src/index.ts`) is used as written. A `main` or `exports["."]` that describes the published
|
|
195
|
+
* layout (`index.js`, `./es6/src/index.js`) is mapped back to the source it was built from,
|
|
196
|
+
* falling back to `src/index.ts` (#518).
|
|
197
|
+
*/ getSourceEntryPath() {
|
|
198
|
+
const projectRoot = _nodepath.default.join(this.rootDir, this.projectDirectory);
|
|
199
|
+
const main = this.packageJson?.main;
|
|
200
|
+
if (main != null && _sourceextensions.sourceExtensions.isSource(main)) {
|
|
201
|
+
return _nodepath.default.join(projectRoot, main);
|
|
202
|
+
}
|
|
203
|
+
const exports1 = this.packageJson?.exports;
|
|
204
|
+
const root = exports1 == null ? undefined : typeof exports1 === "string" ? exports1 : exports1["."] ?? (Object.keys(exports1).some((k)=>k.startsWith(".")) ? undefined : exports1);
|
|
205
|
+
for (const built of [
|
|
206
|
+
root == null ? undefined : firstExportTarget(root),
|
|
207
|
+
main
|
|
208
|
+
]){
|
|
209
|
+
const fromSrc = built?.match(/(?:^|\/)(src\/.+)$/)?.[1];
|
|
210
|
+
const source = fromSrc == null ? undefined : sourceFileFor(_nodepath.default.join(projectRoot, fromSrc));
|
|
211
|
+
if (source != null) return source;
|
|
212
|
+
}
|
|
213
|
+
const conventional = _nodepath.default.join(projectRoot, "src/index.ts");
|
|
214
|
+
if (main == null || (0, _nodefs.existsSync)(conventional)) return conventional;
|
|
215
|
+
return _nodepath.default.join(projectRoot, main);
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* The source file each subpath in package.json `exports` names, such as `./auth` →
|
|
219
|
+
* `<project>/src/auth/auth.extensions.ts` (#518). Exports point at the release layout
|
|
220
|
+
* (`./es6/src/auth/auth.extensions.js`); the source is the part from `src/`, with its
|
|
221
|
+
* TypeScript extension. Wildcard subpaths, and targets with no such source file, are left out.
|
|
222
|
+
*/ getSourceExports() {
|
|
223
|
+
const exports1 = this.packageJson?.exports;
|
|
224
|
+
if (exports1 == null || typeof exports1 === "string") return {};
|
|
225
|
+
const projectRoot = _nodepath.default.join(this.rootDir, this.projectDirectory);
|
|
226
|
+
const sources = {};
|
|
227
|
+
for (const [subpath, target] of Object.entries(exports1)){
|
|
228
|
+
if (!subpath.startsWith("./") || subpath.includes("*")) continue;
|
|
229
|
+
const built = firstExportTarget(target);
|
|
230
|
+
const fromSrc = built?.match(/(?:^|\/)(src\/.+)$/)?.[1];
|
|
231
|
+
if (fromSrc == null) continue;
|
|
232
|
+
const source = sourceFileFor(_nodepath.default.join(projectRoot, fromSrc));
|
|
233
|
+
if (source != null) sources[subpath] = source;
|
|
234
|
+
}
|
|
235
|
+
return sources;
|
|
236
|
+
}
|
|
237
|
+
[Symbol.dispose]() {
|
|
238
|
+
this.stopWatching();
|
|
239
|
+
}
|
|
240
|
+
getWorkspaceOut() {
|
|
241
|
+
const out = _nodepath.default.join(this.#projectConfig.rootDir ?? "./", this.#projectConfig.outDir);
|
|
242
|
+
return out;
|
|
243
|
+
}
|
|
244
|
+
updateSourceFileCache(eventName, file) {
|
|
245
|
+
if (!this.#hasLoadedSourceFiles) {
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
switch(eventName){
|
|
249
|
+
case _io.io.WatchEvents.unlink:
|
|
250
|
+
this.#sourceFiles.delete(file.relativePath);
|
|
251
|
+
return;
|
|
252
|
+
case _io.io.WatchEvents.add:
|
|
253
|
+
case _io.io.WatchEvents.change:
|
|
254
|
+
if (this.matchesSourcePattern(file.relativePath)) {
|
|
255
|
+
this.#sourceFiles.set(file.relativePath, file);
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
this.#sourceFiles.delete(file.relativePath);
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
matchesSourcePattern(relativePath) {
|
|
263
|
+
if (_picomatch.default.isMatch(relativePath, this.ignore)) {
|
|
264
|
+
return false;
|
|
265
|
+
}
|
|
266
|
+
return _picomatch.default.isMatch(relativePath, this.include);
|
|
267
|
+
}
|
|
268
|
+
resolveConfiguration(configurationName) {
|
|
269
|
+
const resolvedConfigurationName = configurationName ?? "debug";
|
|
270
|
+
const configuration = this.configurations.find((c)=>c.name === resolvedConfigurationName);
|
|
271
|
+
if (configuration == null) {
|
|
272
|
+
throw new _errors.WorkspaceConfigurationError(`Configuration "${resolvedConfigurationName}" was not found for project "${this.name}"`);
|
|
273
|
+
}
|
|
274
|
+
return configuration;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
_ts_decorate([
|
|
278
|
+
(0, _caching.memoize)(),
|
|
279
|
+
_ts_metadata("design:type", Function),
|
|
280
|
+
_ts_metadata("design:paramtypes", []),
|
|
281
|
+
_ts_metadata("design:returntype", Promise)
|
|
282
|
+
], Project.prototype, "getAllFiles", null);
|
|
283
|
+
_ts_decorate([
|
|
284
|
+
(0, _caching.cache)(),
|
|
285
|
+
_ts_metadata("design:type", Function),
|
|
286
|
+
_ts_metadata("design:paramtypes", []),
|
|
287
|
+
_ts_metadata("design:returntype", void 0)
|
|
288
|
+
], Project.prototype, "getRootOut", null);
|
|
289
|
+
_ts_decorate([
|
|
290
|
+
(0, _caching.cache)(),
|
|
291
|
+
_ts_metadata("design:type", Function),
|
|
292
|
+
_ts_metadata("design:paramtypes", [
|
|
293
|
+
void 0
|
|
294
|
+
]),
|
|
295
|
+
_ts_metadata("design:returntype", void 0)
|
|
296
|
+
], Project.prototype, "getOutDir", null);
|
|
297
|
+
/** The first path an exports value gives, preferring the conditions that name runtime code. */ function firstExportTarget(value) {
|
|
298
|
+
if (typeof value === "string") return value;
|
|
299
|
+
for (const condition of [
|
|
300
|
+
"import",
|
|
301
|
+
"default",
|
|
302
|
+
"require",
|
|
303
|
+
"node",
|
|
304
|
+
"types"
|
|
305
|
+
]){
|
|
306
|
+
const nested = value[condition];
|
|
307
|
+
if (nested != null) return firstExportTarget(nested);
|
|
308
|
+
}
|
|
309
|
+
return undefined;
|
|
310
|
+
}
|
|
311
|
+
/** The TypeScript source a built or declaration path came from, if it exists. */ function sourceFileFor(builtPath) {
|
|
312
|
+
// A declaration names the file its JavaScript sits next to: `x.d.ts` is `x.js`.
|
|
313
|
+
const declaration = builtPath.match(/^(.*)\.d\.([mc]?)ts$/);
|
|
314
|
+
const built = declaration == null ? builtPath : `${declaration[1]}.${declaration[2]}js`;
|
|
315
|
+
return _sourceextensions.sourceExtensions.candidates(built).find((candidate)=>(0, _nodefs.existsSync)(candidate));
|
|
316
|
+
}
|