Skip to content

Commit

Permalink
add parser for yaml files, check workspaces in pnpm-workspaces.yaml
Browse files Browse the repository at this point in the history
  • Loading branch information
mmews committed Jan 3, 2024
1 parent bc4affa commit 7979fab
Show file tree
Hide file tree
Showing 6 changed files with 334 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,11 @@ public final class N4JSGlobals {
*/
public static final String TS_CONFIG = "tsconfig.json";

/**
* The name of the pnpm-workspace.yaml file.
*/
public static final String PNPM_WORKSPACE = "pnpm-workspace.yaml";

/**
* All project names of n4js libraries.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ public class ProjectDescription extends ImmutableDataClass {
private final boolean esm;
private final boolean moduleProperty;
private final boolean n4jsNature;
private final boolean pnpmWorkspaceRoot;
private final boolean yarnWorkspaceRoot;
private final boolean isGeneratorEnabledSourceMaps;
private final boolean isGeneratorEnabledDts;
Expand All @@ -86,8 +87,8 @@ public ProjectDescription(FileURI location, FileURI relatedRootlocation,
Iterable<ProjectReference> implementedProjects, String outputPath,
Iterable<SourceContainerDescription> sourceContainers, Iterable<ModuleFilter> moduleFilters,
Iterable<ProjectReference> testedProjects, String definesPackage, boolean nestedNodeModulesFolder,
boolean esm, boolean moduleProperty, boolean n4jsNature, boolean yarnWorkspaceRoot,
boolean isGeneratorEnabledSourceMaps, boolean isGeneratorEnabledDts,
boolean esm, boolean moduleProperty, boolean n4jsNature, boolean pnpmWorkspaceRoot,
boolean yarnWorkspaceRoot, boolean isGeneratorEnabledSourceMaps, boolean isGeneratorEnabledDts,
Map<String, String> generatorRewriteModuleSpecifiers, boolean isGeneratorEnabledRewriteCjsImports,
Iterable<String> workspaces, Iterable<String> tsFiles, Iterable<String> tsInclude,
Iterable<String> tsExclude) {
Expand Down Expand Up @@ -121,6 +122,7 @@ public ProjectDescription(FileURI location, FileURI relatedRootlocation,
this.esm = esm;
this.moduleProperty = moduleProperty;
this.n4jsNature = n4jsNature;
this.pnpmWorkspaceRoot = pnpmWorkspaceRoot;
this.yarnWorkspaceRoot = yarnWorkspaceRoot;
this.isGeneratorEnabledSourceMaps = isGeneratorEnabledSourceMaps;
this.isGeneratorEnabledDts = isGeneratorEnabledDts;
Expand Down Expand Up @@ -162,6 +164,7 @@ public ProjectDescription(ProjectDescription template) {
this.esm = template.esm;
this.moduleProperty = template.moduleProperty;
this.n4jsNature = template.n4jsNature;
this.pnpmWorkspaceRoot = template.pnpmWorkspaceRoot;
this.yarnWorkspaceRoot = template.yarnWorkspaceRoot;
this.isGeneratorEnabledSourceMaps = template.isGeneratorEnabledSourceMaps;
this.isGeneratorEnabledDts = template.isGeneratorEnabledDts;
Expand Down Expand Up @@ -207,6 +210,7 @@ public ProjectDescriptionBuilder change() {
builder.setESM(esm);
builder.setModuleProperty(moduleProperty);
builder.setN4JSNature(n4jsNature);
builder.setPnpmWorkspaceRoot(pnpmWorkspaceRoot);
builder.setYarnWorkspaceRoot(yarnWorkspaceRoot);
builder.setGeneratorEnabledSourceMaps(isGeneratorEnabledSourceMaps);
builder.setGeneratorEnabledDts(isGeneratorEnabledDts);
Expand Down Expand Up @@ -387,6 +391,16 @@ public boolean isYarnWorkspaceRoot() {
return yarnWorkspaceRoot;
}

/**
* True iff the project represented by this project description is the root of a pnpm workspace. This flag will be
* {@code true} iff the directory containing a package.json also contains the pnpm-workspace.yaml file with the
* top-level property "packages", no matter the value (i.e. will be {@code true} even if the value is the empty
* array).
*/
public boolean isPnpmWorkspaceRoot() {
return pnpmWorkspaceRoot;
}

/** Returns true iff source maps should be emitted. */
public boolean isGeneratorEnabledSourceMaps() {
return isGeneratorEnabledSourceMaps;
Expand Down Expand Up @@ -513,6 +527,7 @@ protected boolean computeEquals(Object obj) {
&& esm == other.esm
&& moduleProperty == other.moduleProperty
&& n4jsNature == other.n4jsNature
&& pnpmWorkspaceRoot == other.pnpmWorkspaceRoot
&& yarnWorkspaceRoot == other.yarnWorkspaceRoot
&& isGeneratorEnabledSourceMaps == other.isGeneratorEnabledSourceMaps
&& isGeneratorEnabledDts == other.isGeneratorEnabledDts
Expand Down Expand Up @@ -578,6 +593,9 @@ public void toStringAdditionalProperties(StringBuilder sb) {
if (definesPackage != null) {
sb.append(" definesPackage: " + definesPackage + "\n");
}
if (pnpmWorkspaceRoot) {
sb.append(" pnpmWorkspaceRoot: true\n");
}
if (yarnWorkspaceRoot) {
sb.append(" yarnWorkspaceRoot: true\n");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ public class ProjectDescriptionBuilder {
private boolean esm;
private boolean moduleProperty;
private boolean n4jsNature;
private boolean pnpmWorkspaceRoot;
private boolean yarnWorkspaceRoot;
private Boolean isGeneratorEnabledSourceMaps;
private Boolean isGeneratorEnabledDts;
Expand Down Expand Up @@ -84,7 +85,7 @@ public ProjectDescription build() {
exports, extendedRuntimeEnvironment,
providedRuntimeLibraries, requiredRuntimeLibraries, dependencies, implementationId, implementedProjects,
outputPath, sourceContainers, moduleFilters, testedProjects, definesPackage,
nestedNodeModulesFolder, esm, moduleProperty, n4jsNature, yarnWorkspaceRoot,
nestedNodeModulesFolder, esm, moduleProperty, n4jsNature, pnpmWorkspaceRoot, yarnWorkspaceRoot,
isGeneratorEnabledSourceMaps, isGeneratorEnabledDts, generatorRewriteModuleSpecifiers,
isGeneratorEnabledRewriteCjsImports, workspaces, tsFiles, tsInclude, tsExclude);
}
Expand Down Expand Up @@ -378,10 +379,19 @@ public ProjectDescriptionBuilder setN4JSNature(boolean n4jsNature) {
return this;
}

public boolean isPnpmWorkspaceRoot() {
return pnpmWorkspaceRoot;
}

public boolean isYarnWorkspaceRoot() {
return yarnWorkspaceRoot;
}

public ProjectDescriptionBuilder setPnpmWorkspaceRoot(boolean pnpmWorkspaceRoot) {
this.pnpmWorkspaceRoot = pnpmWorkspaceRoot;
return this;
}

public ProjectDescriptionBuilder setYarnWorkspaceRoot(boolean yarnWorkspaceRoot) {
this.yarnWorkspaceRoot = yarnWorkspaceRoot;
return this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

import org.apache.log4j.Logger;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.common.util.WrappedException;
import org.eclipse.emf.ecore.EObject;
Expand All @@ -54,10 +56,10 @@
import org.eclipse.xtext.resource.XtextResourceSet;
import org.eclipse.xtext.util.LazyStringInputStream;
import org.eclipse.xtext.util.Pair;
import org.eclipse.xtext.util.RuntimeIOException;
import org.eclipse.xtext.util.Strings;
import org.eclipse.xtext.util.Tuples;

import com.google.common.collect.Multimap;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
Expand All @@ -73,6 +75,7 @@
*/
@Singleton
public class ProjectDescriptionLoader {
private final static Logger LOGGER = Logger.getLogger(ProjectDescriptionLoader.class);

@Inject
private Provider<XtextResourceSet> resourceSetProvider;
Expand Down Expand Up @@ -111,6 +114,7 @@ public ProjectDescription loadProjectDescriptionAtLocation(FileURI location, URI
if (pdbFromPackageJSON != null) {
setInformationFromFileSystem(location, pdbFromPackageJSON);
setInformationFromTSConfig(location, pdbFromPackageJSON);
setInformationFromPnpmWorkspace(location, pdbFromPackageJSON);
pdbFromPackageJSON.setLocation(location);
pdbFromPackageJSON.setRelatedRootLocation(relatedRootLocation);

Expand Down Expand Up @@ -228,7 +232,7 @@ private void setInformationFromFileSystem(FileURI location, ProjectDescriptionBu
}

/**
* Store some information from {@code tsconfig.json} files iff existent in the project folders root.
* Store some information from {@code tsconfig.json} file iff existent in the project folders root.
*/
private void setInformationFromTSConfig(FileURI location, ProjectDescriptionBuilder target) {
ProjectType type = target.getProjectType();
Expand All @@ -248,7 +252,7 @@ private void setInformationFromTSConfig(FileURI location, ProjectDescriptionBuil
}
}
JSONDocument tsconfig = loadJSONAtLocation(path);
JSONValue content = tsconfig.getContent();
JSONValue content = tsconfig == null ? null : tsconfig.getContent();
if (!(content instanceof JSONObject)) {
return;
}
Expand All @@ -273,6 +277,27 @@ private void setInformationFromTSConfig(FileURI location, ProjectDescriptionBuil
}
}

/**
* Store some information from {@code pnpm-workspaces.yaml} file iff existent in the project folders root.
*/
private void setInformationFromPnpmWorkspace(FileURI location, ProjectDescriptionBuilder target) {
Path path = location.appendSegment(N4JSGlobals.PNPM_WORKSPACE).toFileSystemPath();
if (!Files.isReadable(path)) {
path = location.appendSegment(N4JSGlobals.PNPM_WORKSPACE + "." + N4JSGlobals.XT_FILE_EXTENSION)
.toFileSystemPath();
if (!Files.isReadable(path)) {
return;
}
}

Multimap<String, String> pnpmWorkspacesYaml = YamlUtil.loadYamlAtLocation(path);
Collection<String> packagesEntries = pnpmWorkspacesYaml.get("packages");
if (!packagesEntries.isEmpty()) {
target.setPnpmWorkspaceRoot(true);
target.getWorkspaces().addAll(packagesEntries);
}
}

private JSONDocument loadPackageJSONAtLocation(FileURI location) {
Path path = location.appendSegment(N4JSGlobals.PACKAGE_JSON).toFileSystemPath();
if (!Files.isReadable(path)) {
Expand All @@ -299,7 +324,8 @@ private JSONDocument loadJSONAtLocation(Path path) {
return packageJSON;
}
} catch (IOException e) {
throw new RuntimeIOException(e);
LOGGER.error("Could not load " + path.toString(), e);
return null;
}
}

Expand Down
102 changes: 102 additions & 0 deletions plugins/org.eclipse.n4js/src/org/eclipse/n4js/utils/YamlUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/**
* Copyright (c) 2024 NumberFour AG.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* NumberFour AG - Initial API and implementation
*/
package org.eclipse.n4js.utils;

import static com.google.common.base.Strings.isNullOrEmpty;
import static org.eclipse.n4js.utils.Strings.join;
import static org.eclipse.xtext.xbase.lib.IterableExtensions.filter;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;

import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Multimap;

/**
* Utility for loading yaml files
*/
public class YamlUtil {
private final static Logger LOGGER = Logger.getLogger(YamlUtil.class);

/** Loads a yaml file from the give location */
static public Multimap<String, String> loadYamlAtLocation(Path path) {
try {
List<String> lines = Files.readAllLines(path, StandardCharsets.UTF_8);
return loadYamlFromLines(lines);

} catch (IOException e) {
LOGGER.error("Could not load " + path.toString(), e);
}
return LinkedHashMultimap.create();
}

/** Loads yaml content from the given string */
static public Multimap<String, String> loadYamlFromString(String str) {
return loadYamlFromLines(Arrays.asList(str.split("\n")));
}

/** Loads yaml content from the given lines */
static public Multimap<String, String> loadYamlFromLines(List<String> lines) {
Multimap<String, String> result = LinkedHashMultimap.create();
Map<Integer, String> stack = new LinkedHashMap<>();
for (String line : lines) {
if (line.startsWith("---") || line.startsWith("#")) {
continue;
}
int commentIdx = line.indexOf("#");
if (commentIdx >= 0) {
line = line.substring(0, commentIdx);
}
int leadingSpaces = line.indexOf(line.trim());
line = line.trim();

if (line.startsWith("-")) {
line = line.substring(1).trim();
}
int propNameIdx = line.indexOf(":");
if (propNameIdx >= 0) {
String propName = line.substring(0, propNameIdx).trim();

stack.put(leadingSpaces, propName);
stack.keySet().removeIf(k -> k > leadingSpaces);

String value = line.substring(propNameIdx + 1).trim();
if (!isNullOrEmpty(value)) {
value = trimQuotes(value);
String qpn = join(":", stack.values());
result.put(qpn, value);
}
} else {
line = trimQuotes(line);
String qpn = join(":", e -> e.getValue(), filter(stack.entrySet(), e -> e.getKey() <= leadingSpaces));
result.put(qpn, line);
}
}
return result;
}

static private String trimQuotes(String str) {
if (str.startsWith("\"") && str.endsWith("\"")) {
return str.substring(1, str.length() - 1); // no trim
} else if (str.startsWith("'") && str.endsWith("'")) {
return str.substring(1, str.length() - 1); // no trim
}
return str;
}
}
Loading

0 comments on commit 7979fab

Please sign in to comment.