/** * Visits the containing file of the specified element to find a require to a style sheet file * * @param cssReferencingElement starting point for finding an imported style sheet file * @return the PSI file for the first imported style sheet file */ public static StylesheetFile getImportedStyleSheetFile(PsiElement cssReferencingElement) { final Ref<StylesheetFile> file = new Ref<>(); cssReferencingElement.getContainingFile().accept(new PsiRecursiveElementVisitor() { @Override public void visitElement(PsiElement element) { if (file.get() != null) { return; } if (element instanceof JSLiteralExpression) { if (resolveStyleSheetFile(element, file)) return; } if(element instanceof ES6FromClause) { if (resolveStyleSheetFile(element, file)) return; } super.visitElement(element); } }); return file.get(); }
/** * Gets the import/require declaration that a string literal belongs to, e.g 'normal' -> * 'const styles = require("./foo.css")' or 'import styles from "./foo.css"' based on <code>styles['normal']</code> * * @param classNameLiteral a string literal that is potentially a CSS class name * @return the JS variable that is a potential require of a style sheet file, or <code>null</code> if the PSI structure doesn't match */ public static PsiElement getCssClassNamesImportOrRequireDeclaration(JSLiteralExpression classNameLiteral) { final JSIndexedPropertyAccessExpression expression = PsiTreeUtil.getParentOfType(classNameLiteral, JSIndexedPropertyAccessExpression.class); if (expression != null) { // string literal is part of "var['string literal']", e.g. "styles['normal']" if (expression.getQualifier() != null) { final PsiReference psiReference = expression.getQualifier().getReference(); if (psiReference != null) { final PsiElement varReference = psiReference.resolve(); if (varReference instanceof JSVariable) { return varReference; } if(varReference instanceof ES6ImportedBinding) { return varReference.getParent(); } } } } return null; }
/** * Resolves the style sheet PSI file that backs a require("./stylesheet.css"). * * @param cssFileNameLiteralParent parent element to a file name string literal that points to a style sheet file * @return the matching style sheet PSI file, or <code>null</code> if the file can't be resolved */ public static StylesheetFile resolveStyleSheetFile(PsiElement cssFileNameLiteralParent) { final Ref<StylesheetFile> stylesheetFileRef = new Ref<>(); cssFileNameLiteralParent.accept(new PsiRecursiveElementVisitor() { @Override public void visitElement(PsiElement element) { if (stylesheetFileRef.get() != null) { return; } if (element instanceof JSLiteralExpression) { if (resolveStyleSheetFile(element, stylesheetFileRef)) return; } if(element instanceof ES6FromClause) { if (resolveStyleSheetFile(element, stylesheetFileRef)) return; } super.visitElement(element); } }); return stylesheetFileRef.get(); }
private void attachSnippets(@NotNull PsiElement sourceElement, @NotNull List<PsiElement> targets) { PsiElement parent = sourceElement.getParent(); if(!(parent instanceof JSLiteralExpression)) { return; } Object value = ((JSLiteralExpression) parent).getValue(); if(!(value instanceof String) || StringUtils.isBlank((String) value) || !((String) value).startsWith("{s")) { return; } String name = ExtJsUtil.getAttributeTagValueFromSmartyString("s", "name", (String) value); if(name == null) { return; } String namespace = ExtJsUtil.getNamespaceFromStringLiteral((JSLiteralExpression) parent); if(namespace == null) { return; } targets.addAll(SnippetUtil.getSnippetNameTargets(parent.getProject(), namespace, name)); }
private static PsiElementPattern.Capture<JSLiteralExpression> literalInProperty(final String propertyName) { return PlatformPatterns.psiElement(JSLiteralExpression.class).and(new FilterPattern(new ElementFilter() { @Override public boolean isAcceptable(Object element, @Nullable PsiElement context) { if (element instanceof JSLiteralExpression) { final JSLiteralExpression literal = (JSLiteralExpression)element; if (literal.isQuotedLiteral()) { final PsiElement parent = literal.getParent(); if (parent instanceof JSProperty && propertyName.equals(((JSProperty)parent).getName())) { return EmberIndexUtil.hasEmberJS(literal.getProject()); } } } return false; } @Override public boolean isClassAcceptable(Class hintClass) { return true; } })); }
@RequiredReadAction @Override @SuppressWarnings("unchecked") public T parseValue(@NotNull Class type, @NotNull Type genericType, @NotNull PsiElement value) throws JomBadValueExpressionException { if(value instanceof JSLiteralExpression) { IElementType elementType = PsiUtilCore.getElementType(value.getFirstChild()); if(elementType == JSTokenTypes.NUMERIC_LITERAL) { try { return (T) myParseMethodValue.getValue().invoke(null, value.getText()); } catch(Exception e) { throw new JomBadValueExpressionException(e); } } } throw new JomBadValueExpressionException(); }
@RequiredReadAction @Override public Boolean parseValue(@NotNull Class type, @NotNull Type genericType, @NotNull PsiElement value) throws JomBadValueExpressionException { if(value instanceof JSLiteralExpression) { IElementType elementType = PsiUtilCore.getElementType(value.getFirstChild()); if(elementType == JSTokenTypes.TRUE_KEYWORD) { return Boolean.TRUE; } else if(elementType == JSTokenTypes.FALSE_KEYWORD) { return Boolean.FALSE; } } throw new JomBadValueExpressionException(); }
@Override public void visitJSBinaryExpression(@NotNull JSBinaryExpression expression) { super.visitJSBinaryExpression(expression); if (!(expression.getROperand() != null)) { return; } if (!ComparisonUtils.isComparison(expression)) { return; } final JSExpression lhs = expression.getLOperand(); final JSExpression rhs = expression.getROperand(); if (lhs instanceof JSLiteralExpression || !(rhs instanceof JSLiteralExpression)) { return; } registerError(expression); }
@Override public void visitJSBinaryExpression(@NotNull JSBinaryExpression expression) { super.visitJSBinaryExpression(expression); if (!(expression.getROperand() != null)) { return; } if (!ComparisonUtils.isComparison(expression)) { return; } final JSExpression lhs = expression.getLOperand(); final JSExpression rhs = expression.getROperand(); if (!(lhs instanceof JSLiteralExpression) || rhs instanceof JSLiteralExpression) { return; } registerError(expression); }
public static BigInteger getLiteralNumber(JSLiteralExpression expression) { String expressionText = expression.getText(); int radix = 10; if (expressionText == null || expressionText.length() == 0) { return new BigInteger(new byte[] { 0 }); } if (expressionText.charAt(0) == '0') { if (expressionText.length() > 2 && Character.toUpperCase(expressionText.charAt(1)) == 'X') { expressionText = expressionText.substring(2); radix = 16; } else if (octalPattern.matcher(expressionText).matches()) { radix = 8; } } return new BigInteger(expressionText, radix); }
@Override public void processIntention(@NotNull PsiElement element) throws IncorrectOperationException { final JSBinaryExpression expression = (JSBinaryExpression) element; final JSExpression lhs = expression.getLOperand(); final JSExpression rhs = expression.getROperand(); assert (lhs instanceof JSLiteralExpression && rhs instanceof JSLiteralExpression); final JSLiteralExpression leftLiteral = (JSLiteralExpression) lhs; final JSLiteralExpression rightLiteral = (JSLiteralExpression) rhs; String lhsText = lhs.getText(); String rhsText = rhs.getText(); final String newExpression; if (StringUtil.isSimpleQuoteStringLiteral(leftLiteral) && StringUtil.isDoubleQuoteStringLiteral(rightLiteral)) { rhsText = JSDoubleToSingleQuotedStringIntention.changeQuotes(rhsText); } else if (StringUtil.isDoubleQuoteStringLiteral(leftLiteral) && StringUtil.isSimpleQuoteStringLiteral(rightLiteral)) { rhsText = JSSingleToDoubleQuotedStringIntention.changeQuotes(rhsText); } newExpression = lhsText.substring(0, lhsText.length() - 1) + rhsText.substring(1); JSElementFactory.replaceExpression(expression, newExpression); }
public static boolean isPowerOfTwo(JSExpression expression) { if (!(expression instanceof JSLiteralExpression)) { return false; } final String value = expression.getText(); long intValue; try { intValue = Integer.decode(value).longValue(); } catch (NumberFormatException e) { return false; } if (intValue <= 0) { return false; } while ((intValue & 1) == 0) { intValue >>= 1; } return (intValue == 1); }
public static boolean isIntLiteral(JSExpression expression) { if (!(expression instanceof JSLiteralExpression)) { return false; } if (!(expression instanceof JSLiteralExpression)) { return false; } final String value = expression.getText(); try { Integer.decode(value); return true; } catch (NumberFormatException e) { return false; } }
@Override public boolean isAcceptable(Object element, @Nullable PsiElement context) { if (element instanceof JSLiteralExpression && context != null && context.getContainingFile() instanceof JSFile) { final ASTNode value = ((JSLiteralExpression) element).getNode().getFirstChildNode(); return value != null && value.getElementType() == JSTokenTypes.STRING_LITERAL; } return false; }
@Override public void registerReferenceProviders(@NotNull PsiReferenceRegistrar registrar) { registrar.registerReferenceProvider(CssModulesUtil.STRING_PATTERN, new PsiReferenceProvider() { @NotNull @Override public PsiReference[] getReferencesByElement(@NotNull PsiElement element, @NotNull ProcessingContext context) { final PsiElement cssClassNamesImportOrRequire = CssModulesUtil.getCssClassNamesImportOrRequireDeclaration((JSLiteralExpression) element); if (cssClassNamesImportOrRequire != null) { final String literalClass = "." + StringUtils.stripStart(StringUtils.stripEnd(element.getText(), "\"'"), "\"'"); final Ref<StylesheetFile> referencedStyleSheet = new Ref<>(); final CssClass cssClass = CssModulesUtil.getCssClass(cssClassNamesImportOrRequire, literalClass, referencedStyleSheet); if (cssClass != null) { return new PsiReference[]{new PsiReferenceBase<PsiElement>(element) { @Nullable @Override public PsiElement resolve() { return cssClass; } @NotNull @Override public Object[] getVariants() { return new Object[0]; } }}; } else { if (referencedStyleSheet.get() != null) { final TextRange rangeInElement = TextRange.from(1, element.getTextLength() - 2); // minus string quotes return new PsiReference[]{new CssModulesUnknownClassPsiReference(element, rangeInElement, referencedStyleSheet.get())}; } } } return new PsiReference[0]; } }); }
@NotNull @Override public ThreeState shouldSkipAutopopup(@NotNull PsiElement contextElement, @NotNull PsiFile psiFile, int offset) { if (contextElement.getParent() instanceof JSLiteralExpression) { final PsiElement cssClassNamesImportOrRequire = CssModulesUtil.getCssClassNamesImportOrRequireDeclaration((JSLiteralExpression) contextElement.getParent()); if (cssClassNamesImportOrRequire != null) { final StylesheetFile stylesheetFile = CssModulesUtil.resolveStyleSheetFile(cssClassNamesImportOrRequire); if (stylesheetFile != null) { return ThreeState.NO; } } } return ThreeState.UNSURE; }
@Override public void annotate(@NotNull PsiElement psiElement, @NotNull AnnotationHolder annotationHolder) { PsiElement elementToAnnotate = null; if (psiElement instanceof XmlAttributeValue) { if (CssModulesUtil.STYLE_NAME_FILTER.isAcceptable(psiElement, psiElement)) { elementToAnnotate = psiElement; } } else if (psiElement instanceof JSLiteralExpression) { elementToAnnotate = psiElement; } if (elementToAnnotate != null) { for (PsiReference psiReference : psiElement.getReferences()) { if (psiReference instanceof CssModulesUnknownClassPsiReference) { final TextRange rangeInElement = psiReference.getRangeInElement(); if (rangeInElement.isEmpty()) { continue; } int start = psiElement.getTextRange().getStartOffset() + rangeInElement.getStartOffset(); int length = rangeInElement.getLength(); final TextRange textRange = TextRange.from(start, length); if (!textRange.isEmpty()) { final String message = "Unknown class name \"" + rangeInElement.substring(psiElement.getText()) + "\""; annotationHolder.createErrorAnnotation(textRange, message); } } } } }
private PsiElement getIntentionElement(@NotNull PsiElement element) { PsiElement intentionElement; if (element instanceof XmlToken) { intentionElement = PsiTreeUtil.getParentOfType(element, XmlAttributeValue.class); } else { intentionElement = PsiTreeUtil.getParentOfType(element, JSLiteralExpression.class); if (intentionElement == null) { intentionElement = PsiTreeUtil.getPrevSiblingOfType(element, JSLiteralExpression.class); } } return intentionElement; }
/** * String must start with "{s" */ private PsiElementPattern.Capture<PsiElement> getSnippetPattern() { return PlatformPatterns.psiElement() .withParent(PlatformPatterns.psiElement(JSLiteralExpression.class) .with(new PatternCondition<JSLiteralExpression>("Snippet Start") { @Override public boolean accepts(@NotNull JSLiteralExpression jsLiteralExpression, ProcessingContext processingContext) { Object value = jsLiteralExpression.getValue(); return value instanceof String && (((String) value).startsWith("{s")); } })); }
/** * {header: '{s name=swag-last-registrations/date}{/s}'} */ @Nullable public static String getNamespaceFromStringLiteral(@NotNull JSLiteralExpression element) { Object contents = element.getValue(); if(!(contents instanceof String) || StringUtils.isBlank((String) contents)) { return null; } String namespace = getAttributeTagValueFromSmartyString("s", "namespace", (String) contents); if(namespace != null) { return namespace; } return getSnippetNamespaceFromFile(element.getContainingFile()); }
/** * @see ExtJsUtil#getNamespaceFromStringLiteral */ public void testGetNamespaceFromStringLiteral() { myFixture.configureByText( JavaScriptFileType.INSTANCE, "var foo = { foo: \"{s name=backend/inde<caret>x/view/widgets namespace='foobar'}\"}" ); PsiElement psiElement = myFixture.getFile().findElementAt(myFixture.getCaretOffset()).getParent(); assertEquals("foobar", ExtJsUtil.getNamespaceFromStringLiteral((JSLiteralExpression) psiElement)); }
@NotNull @Override public PsiReference[] getReferencesByElement(@NotNull PsiElement element, @NotNull ProcessingContext context) { final FileReferenceSet fileReferenceSet = new FileReferenceSet(element) { @Override protected boolean isSoft() { return true; } }; return ArrayUtil.mergeArrays(fileReferenceSet.getAllReferences(), new PsiReference[] {new EmberJSTemplateCacheReference((JSLiteralExpression)element)}); }
@Nullable public static JSNamedElementProxy getComponent(@Nullable PsiElement element) { if (element instanceof JSNamedElementProxy) { return getComponent(element, ((JSNamedElementProxy)element).getName()); } if (element instanceof JSLiteralExpression && ((JSLiteralExpression)element).isQuotedLiteral()) { return getComponent(element, StringUtil.unquoteString(element.getText())); } return null; }
protected @Nullable JSElement getDefineLiteral(PsiElement elementAtCaretPosition, DefineStatement defineStatement) { iterations += 1; if(elementAtCaretPosition == null || iterations > 10) { return null; } if(elementAtCaretPosition.getParent() instanceof JSLiteralExpression) { return (JSElement) elementAtCaretPosition.getParent(); } if(elementAtCaretPosition.getPrevSibling() instanceof JSLiteralExpression) { return (JSElement) elementAtCaretPosition.getPrevSibling(); } // I know I know ... but this accounts for the case where the cursor is right after the comma so it's a special case if(elementAtCaretPosition.getPrevSibling() != null && elementAtCaretPosition.getPrevSibling().getPrevSibling() instanceof JSLiteralExpression) { return (JSElement) elementAtCaretPosition.getPrevSibling().getPrevSibling(); } // if none of the above cases work, we assume this is a parameter and find its corresponding literal JSElement parameter = getParameter(elementAtCaretPosition, defineStatement); if(parameter == null) { return null; } int parameterIndex = getIndexOfParameter(defineStatement, parameter); if(parameterIndex >= defineStatement.getArguments().getExpressions().length) { return null; } return defineStatement.getArguments().getExpressions()[parameterIndex]; }
private static boolean isTrue(JSExpression expression) { if (expression == null) { return false; } if (!(expression instanceof JSLiteralExpression)) { return false; } @NonNls final String text = expression.getText(); return "true".equals(text); }
private static boolean isFalse(JSExpression expression) { if (expression == null) { return false; } if (!(expression instanceof JSLiteralExpression)) { return false; } @NonNls final String text = expression.getText(); return "false".equals(text); }
private static boolean isFloatingPoint(JSLiteralExpression literal) { final String text = literal.getText(); final char firstChar = text.charAt(0); if (firstChar != '.' && !Character.isDigit(firstChar)) { return false; } return text.contains(".") || text.contains("e") || text.contains("E"); }
private static boolean isString(JSExpression expression) { if (expression instanceof JSLiteralExpression) { final String s = expression.getText(); return s.startsWith("'") || s.startsWith("\""); } return false; }
private boolean isZero(JSExpression expression) { if (m_ignoreExpressionsContainingConstants && !(expression instanceof JSLiteralExpression)) { return false; } final Object value = ExpressionUtil.computeConstantExpression(expression); return value instanceof Integer && (Integer) value == 0; }
private boolean isAllOnes(JSExpression expression) { if (m_ignoreExpressionsContainingConstants && !(expression instanceof JSLiteralExpression)) { return false; } final Object value = ExpressionUtil.computeConstantExpression(expression); return value != null && value instanceof Integer && (Integer) value == 0xffffffff; }
public static boolean isBooleanLiteral(JSExpression condition) { if (!(condition instanceof JSLiteralExpression)) { return false; } final String text = condition.getText(); return (TRUE.equals(text) || FALSE.equals(text)); }
public static Boolean getBooleanLiteral(JSExpression condition) { if (!(condition instanceof JSLiteralExpression)) { return null; } final String text = condition.getText(); return (TRUE .equals(text) ? Boolean.TRUE : FALSE.equals(text) ? Boolean.FALSE : null); }
@Override public boolean satisfiedBy(@NotNull PsiElement element) { if (!(element instanceof JSExpression)) { return false; } if (ErrorUtil.containsError(element)) { return false; } final JSExpression expression = (JSExpression) element; if (element instanceof JSLiteralExpression || ( element instanceof JSReferenceExpression && ((JSReferenceExpression)element).getQualifier() != null ) || expression instanceof JSCallExpression ) { return false; } if (!ExpressionUtil.isConstantExpression(expression)) { return false; } if (ExpressionUtil.computeConstantExpression(expression) == null) { return false; } final PsiElement parent = element.getParent(); if (!(parent instanceof JSExpression)) { return true; } return (!ExpressionUtil.isConstantExpression((JSExpression) parent)); }
@Override public boolean satisfiedBy(@NotNull PsiElement element) { if (!(element instanceof JSLiteralExpression)) { return false; } return StringUtil.isDoubleQuoteStringLiteral((JSLiteralExpression) element); }
@Override public boolean satisfiedBy(@NotNull PsiElement element) { if (!(element instanceof JSLiteralExpression)) { return false; } final JSLiteralExpression expression = (JSLiteralExpression) element; return StringUtil.isSimpleQuoteStringLiteral(expression); }
public static boolean isSimpleQuoteStringLiteral(JSLiteralExpression expression) { final String value = expression.getText(); return (value != null && value.charAt(0) == SIMPLE_QUOTE && value.charAt(value.length() - 1) == SIMPLE_QUOTE); }
public static boolean isDoubleQuoteStringLiteral(JSLiteralExpression expression) { final String value = expression.getText(); return (value != null && value.charAt(0) == DOUBLE_QUOTE && value.charAt(value.length() - 1) == DOUBLE_QUOTE); }
@Override public boolean satisfiedBy(@NotNull PsiElement element) { if (!(element instanceof JSLiteralExpression)) { return false; } return NumberUtil.isDecimal(element.getText()); }
@Override public boolean satisfiedBy(@NotNull PsiElement element) { if (!(element instanceof JSLiteralExpression)) { return false; } final String elementText = element.getText(); return (NumberUtil.isHex (elementText) || NumberUtil.isOctal(elementText)); }
@Override public boolean satisfiedBy(@NotNull PsiElement element) { if (!(element instanceof JSLiteralExpression)) { return false; } final String elementText = element.getText(); return (NumberUtil.isHex (elementText) || (NumberUtil.isDecimal(elementText) && !NumberUtil.isOctal (elementText))); }