lodash#partial TypeScript Examples

The following examples show how to use lodash#partial. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: packet.utils.ts    From nestjs-jaeger-tracing with MIT License 6 votes vote down vote up
export function isRequestPacket<T>(
  packet: unknown,
): packet is RequestPacket<T> {
  const keys: Array<keyof RequestPacket<T>> = ['id', 'data', 'pattern'];
  return every(keys, partial(has, packet));
}
Example #2
Source File: packet.utils.ts    From nestjs-jaeger-tracing with MIT License 6 votes vote down vote up
export function isTracingContext(packet: unknown): packet is TracingContext {
  const keys: Array<keyof TracingContext> = ['payload', 'isSerialized'];
  return every(keys, partial(has, packet));
}
Example #3
Source File: convert.ts    From ui5-language-assistant with Apache License 2.0 6 votes vote down vote up
function convertNamespace(
  libName: string,
  symbol: apiJson.NamespaceSymbol | apiJson.DatatypeSymbol
): model.UI5Namespace {
  const base = convertSymbol(libName, symbol);
  const namespace: model.UI5Namespace = {
    ...base,
    kind: "UI5Namespace",
    fields: [],
    methods: [],
    events: [],
    namespaces: newMap(),
    classes: newMap(),
  };

  namespace.methods = map(
    symbol.methods,
    partial(convertMethod, libName, namespace)
  );
  namespace.fields = map(
    symbol.properties,
    partial(convertField, libName, namespace)
  );
  namespace.events = map(
    symbol.events,
    partial(convertEvent, libName, namespace)
  );

  return namespace;
}
Example #4
Source File: convert.ts    From ui5-language-assistant with Apache License 2.0 6 votes vote down vote up
function convertInterface(
  libName: string,
  symbol: apiJson.InterfaceSymbol
): model.UI5Interface {
  const base = convertSymbol(libName, symbol);
  const interfacee: model.UI5Interface = {
    ...base,
    kind: "UI5Interface",
    events: [],
    methods: [],
  };

  interfacee.events = map(
    symbol.events,
    partial(convertEvent, libName, interfacee)
  );
  interfacee.methods = map(
    symbol.methods,
    partial(convertMethod, libName, interfacee)
  );

  return interfacee;
}
Example #5
Source File: convert.ts    From ui5-language-assistant with Apache License 2.0 6 votes vote down vote up
function convertEnum(
  libName: string,
  symbol: apiJson.EnumSymbol
): model.UI5Enum {
  const base = convertSymbol(libName, symbol);
  const enumm: model.UI5Enum = {
    ...base,
    kind: "UI5Enum",
    fields: [],
  };

  enumm.fields = map(
    symbol.properties,
    partial(convertEnumValue, libName, enumm)
  );

  return enumm;
}
Example #6
Source File: flatten-members.ts    From ui5-language-assistant with Apache License 2.0 5 votes vote down vote up
flattenAggregations = partial(
  flattenMembers,
  (_) => _.aggregations
)
Example #7
Source File: namespace-spec.ts    From ui5-language-assistant with Apache License 2.0 5 votes vote down vote up
expectNamespaceValuesSuggestions = partial(expectSuggestions, (_) => {
  expect(_.type).to.equal("UI5NamespacesInXMLAttributeValue");
  const namespaceSuggestion = _ as UI5NamespacesInXMLAttributeValueCompletion;
  expectUI5Namespace(namespaceSuggestion.ui5Node);
  expectXMLAttribute(namespaceSuggestion.astNode);
  return ui5NodeToFQN(namespaceSuggestion.ui5Node);
})
Example #8
Source File: prop-event-assoc-spec.ts    From ui5-language-assistant with Apache License 2.0 5 votes vote down vote up
expectAttributesNames = partial(expectSuggestions, (_) => _.ui5Node.name)
Example #9
Source File: namespace-spec.ts    From ui5-language-assistant with Apache License 2.0 5 votes vote down vote up
expectNamespaceKeysSuggestions = partial(expectSuggestions, (_) => {
  expect(_.type).to.equal("UI5NamespacesInXMLAttributeKey");
  const namespaceInKey = _ as UI5NamespacesInXMLAttributeKeyCompletion;
  expectUI5Namespace(namespaceInKey.ui5Node);
  expectXMLAttribute(namespaceInKey.astNode);
  return ui5NodeToFQN(namespaceInKey.ui5Node);
})
Example #10
Source File: convert.ts    From ui5-language-assistant with Apache License 2.0 5 votes vote down vote up
function convertClass(
  libName: string,
  symbol: apiJson.ClassSymbol
): model.UI5Class {
  const base = convertSymbol(libName, symbol);
  const clazz: model.UI5Class = {
    ...base,
    kind: "UI5Class",
    abstract: symbol.abstract ?? false,
    ctor: undefined,
    extends: undefined, // Filled later
    implements: [], // Filled later
    aggregations: [],
    associations: [],
    events: [],
    methods: [],
    properties: [],
    fields: [],
    defaultAggregation: undefined, // Filled later
  };

  if (symbol["ui5-metadata"] !== undefined) {
    clazz.aggregations = map(symbol["ui5-metadata"].aggregations, (_) =>
      convertAggregation(libName, _, clazz)
    );
    clazz.associations = map(symbol["ui5-metadata"].associations, (_) =>
      convertAssociation(libName, _, clazz)
    );
    clazz.properties = map(
      symbol["ui5-metadata"].properties,
      partial(convertProperty, libName, clazz)
    );
    // Add special settings (for example: "id" from ManagedObject)
    clazz.properties = clazz.properties.concat(
      map(
        symbol["ui5-metadata"].specialSettings,
        partial(convertProperty, libName, clazz)
      )
    );
  }

  // Due to unfortunate naming, if not defined in the json, symbol.constructor will be a javascript function
  clazz.ctor =
    symbol.constructor === undefined || isFunction(symbol.constructor)
      ? undefined
      : convertConstructor(libName, clazz, symbol.constructor);
  clazz.events = map(symbol.events, partial(convertEvent, libName, clazz));
  clazz.methods = map(symbol.methods, partial(convertMethod, libName, clazz));
  // The "properties" directly under the class symbol are displayed as "fields" in the SDK and are not considered properties
  clazz.fields = map(
    symbol.properties,
    partial(convertProperty, libName, clazz)
  );

  return clazz;
}
Example #11
Source File: flatten-members.ts    From ui5-language-assistant with Apache License 2.0 5 votes vote down vote up
flattenAssociations = partial(
  flattenMembers,
  (_) => _.associations
)
Example #12
Source File: flatten-members.ts    From ui5-language-assistant with Apache License 2.0 5 votes vote down vote up
flattenEvents = partial(flattenMembers, (_) => _.events)
Example #13
Source File: flatten-members.ts    From ui5-language-assistant with Apache License 2.0 5 votes vote down vote up
flattenProperties = partial(flattenMembers, (_) => _.properties)
Example #14
Source File: unknown-attribute-key-spec.ts    From ui5-language-assistant with Apache License 2.0 4 votes vote down vote up
describe("the unknown attribute name validation", () => {
  let ui5SemanticModel: UI5SemanticModel;

  before(async () => {
    ui5SemanticModel = await generateModel({
      version: "1.74.0",
      modelGenerator: generate,
    });
  });

  context("true positive scenarios", () => {
    let assertSingleIssue: (xmlSnippet: string, message: string) => void;
    before(() => {
      assertSingleIssue = partial(
        assertSingleIssueBase,
        ui5SemanticModel,
        {
          attribute: [validators.validateUnknownAttributeKey],
        },
        "UnknownAttributeKey",
        "error"
      );
    });

    it("will detect an invalid attribute key in root class element", () => {
      assertSingleIssue(
        `<mvc:View
          xmlns:mvc="sap.ui.core.mvc"
          xmlns="sap.m"
          ?busy_TYPO?="true">
        </mvc:View>`,
        "Unknown attribute key: busy_TYPO"
      );
    });

    it("will detect an invalid attribute key when the key starts with :", () => {
      assertSingleIssue(
        `<mvc:View
          xmlns:mvc="sap.ui.core.mvc"
          xmlns="sap.m"
          ?:busy?="true">
        </mvc:View>`,
        "Unknown attribute key: :busy"
      );
    });

    it("will detect an invalid attribute key when the key ends with :", () => {
      assertSingleIssue(
        `<mvc:View
          xmlns:mvc="sap.ui.core.mvc"
          xmlns="sap.m"
          ?busy:?="true">
        </mvc:View>`,
        "Unknown attribute key: busy:"
      );
    });

    it("will detect an invalid attribute key in non-root class element", () => {
      assertSingleIssue(
        `<mvc:View
          xmlns:mvc="sap.ui.core.mvc"
          xmlns="sap.m">
          <mvc:content>
            <List ?TYPO?=""></List>
          </mvc:content>
        </mvc:View>`,
        "Unknown attribute key: TYPO"
      );
    });

    it("will detect an invalid attribute key when the attribute doesn't have a value", () => {
      assertSingleIssue(
        `<mvc:View
          xmlns:mvc="sap.ui.core.mvc"
          xmlns="sap.m"
          ?busy_TYPO? >
        </mvc:View>`,
        "Unknown attribute key: busy_TYPO"
      );
    });

    it("will detect an invalid attribute key in aggregation element", () => {
      assertSingleIssue(
        `<mvc:View
          xmlns:mvc="sap.ui.core.mvc"
          xmlns="sap.m">
          <mvc:content ?TYPO?="">
            <List></List>
          </mvc:content>
        </mvc:View>`,
        "Unknown attribute key: TYPO"
      );
    });

    it("will detect an invalid xmlns attribute key element - no prefix", () => {
      assertSingleIssue(
        `<mvc:View
          xmlns:mvc="sap.ui.core.mvc"
          xmlns="sap.m"
          ?xmlns:?="my.ns">
        </mvc:View>`,
        "Unknown attribute key: xmlns:"
      );
    });

    it("will detect an invalid xmlns attribute key element - more than 1 colon", () => {
      assertSingleIssue(
        `<mvc:View
          xmlns:mvc="sap.ui.core.mvc"
          ?xmlns:m:1?="sap.m">
        </mvc:View>`,
        "Unknown attribute key: xmlns:m:1"
      );
    });

    it("will detect 'stashed' as invalid in aggregation element", () => {
      assertSingleIssue(
        `<mvc:View
          xmlns:mvc="sap.ui.core.mvc"
          xmlns="sap.m">
          <mvc:content ?stashed?="">
            <List></List>
          </mvc:content>
        </mvc:View>`,
        "Unknown attribute key: stashed"
      );
    });

    it("will detect 'binding' as invalid in aggregation element", () => {
      assertSingleIssue(
        `<mvc:View
          xmlns:mvc="sap.ui.core.mvc"
          xmlns="sap.m">
          <mvc:content ?binding?="">
            <List></List>
          </mvc:content>
        </mvc:View>`,
        "Unknown attribute key: binding"
      );
    });

    it("will detect 'class' as invalid in aggregation element", () => {
      assertSingleIssue(
        `<mvc:View
          xmlns:mvc="sap.ui.core.mvc"
          xmlns="sap.m">
          <mvc:content ?class?="">
            <List></List>
          </mvc:content>
        </mvc:View>`,
        "Unknown attribute key: class"
      );
    });

    it("will detect 'require' as invalid attribute when it's not in the core or template namespace", () => {
      assertSingleIssue(
        `<mvc:View
          xmlns:mvc="sap.ui.core.mvc"
          xmlns="sap.m"
          ?mvc:require?="">
        </mvc:View>`,
        "Unknown attribute key: mvc:require"
      );
    });

    it("will detect a non-public attribute key in class element", () => {
      // Check that the property exists in the model
      const ui5Class = ui5SemanticModel.classes["sap.uxap.AnchorBar"];
      expectExists(ui5Class, "sap.uxap.AnchorBar");
      const _selectProperty = find(ui5Class.aggregations, ["name", "_select"]);
      expectExists(_selectProperty, "_select");

      assertSingleIssue(
        `<mvc:View
          xmlns:mvc="sap.ui.core.mvc"
          xmlns:uxap="sap.uxap">
          <mvc:content>
            <uxap:AnchorBar ?_select?=""></uxap:AnchorBar>
          </mvc:content>
        </mvc:View>`,
        "Unknown attribute key: _select"
      );
    });
  });

  context("negative edge cases", () => {
    let assertNoIssues: (xmlSnippet: string) => void;
    before(() => {
      assertNoIssues = partial(assertNoIssuesBase, ui5SemanticModel, {
        attribute: [validators.validateUnknownAttributeKey],
      });
    });

    context("class tag", () => {
      it("will not detect an issue when the attribute is a property", () => {
        assertNoIssues(`
          <mvc:View
            xmlns:mvc="sap.ui.core.mvc"
            xmlns="sap.m"
            busy="true">
          </mvc:View>`);
      });

      it("will not detect an issue when the attribute is an event", () => {
        assertNoIssues(`
          <mvc:View
            xmlns:mvc="sap.ui.core.mvc"
            xmlns="sap.m"
            afterInit="true">
          </mvc:View>`);
      });

      it("will not detect an issue when the attribute is an association", () => {
        assertNoIssues(`
          <mvc:View
            xmlns:mvc="sap.ui.core.mvc"
            xmlns="sap.m">
            <mvc:content>
              <m:List ariaLabelledBy="abc"></m:List>
            </mvc:content>
          </mvc:View>`);
      });

      it("will not detect an issue when the attribute is an aggrgation", () => {
        assertNoIssues(`
          <mvc:View
            xmlns:mvc="sap.ui.core.mvc"
            xmlns="sap.m"
            content="{model>elements}">
          </mvc:View>`);
      });

      context("special attributes", () => {
        it("will not detect an issue when the attribute is 'core:require'", () => {
          assertNoIssues(`
            <mvc:View
              xmlns:mvc="sap.ui.core.mvc"
              xmlns:core="sap.ui.core"
              core:require="">
            </mvc:View>`);
        });

        it("will not detect an issue when the attribute is 'sap.ui.dt:designtime'", () => {
          assertNoIssues(`
            <mvc:View
              xmlns:mvc="sap.ui.core.mvc"
              xmlns:dt="sap.ui.dt"
              dt:designtime="">
            </mvc:View>`);
        });

        it("will not detect an issue when the attribute is 'template:require'", () => {
          assertNoIssues(`
            <mvc:View
              xmlns:mvc="sap.ui.core.mvc"
              xmlns:template="http://schemas.sap.com/sapui5/extension/sap.ui.core.template/1"
              template:require="">
            </mvc:View>`);
        });

        it("will not detect an issue when the attribute is 'binding'", () => {
          assertNoIssues(`
            <mvc:View
              xmlns:mvc="sap.ui.core.mvc"
              binding="{}">
            </mvc:View>`);
        });

        it("will not detect an issue when the attribute is 'class'", () => {
          assertNoIssues(`
            <mvc:View
              xmlns:mvc="sap.ui.core.mvc"
              class="small">
            </mvc:View>`);
        });

        it("will not detect an issue when the attribute namespace is custom data", () => {
          assertNoIssues(`
            <mvc:View
              xmlns:mvc="sap.ui.core.mvc"
              xmlns:custom="http://schemas.sap.com/sapui5/extension/sap.ui.core.CustomData/1"
              custom:unknownattr="">
            </mvc:View>`);
        });

        it("will not detect an issue when the attribute is 'stashed' on sap.uxap.ObjectPageLazyLoader", () => {
          assertNoIssues(`
            <mvc:View
                xmlns:mvc="sap.ui.core.mvc"
                xmlns:uxap="sap.uxap">
              <mvc:content>
                <uxap:ObjectPageLazyLoader stashed="true"></uxap:ObjectPageLazyLoader>
              </mvc:content>
            </mvc:View>`);
        });

        it("will not detect an issue when the attribute is xmlns (default)", () => {
          assertNoIssues(`
            <mvc:View
              xmlns:mvc="sap.ui.core.mvc">
              <mvc:content>
                <List xmlns="sap.m"></List>
              </mvc:content>
            </mvc:View>`);
        });

        it("will not detect an issue when the attribute is xmlns (with name)", () => {
          assertNoIssues(`
            <mvc:View
              xmlns:mvc="sap.ui.core.mvc"">
              <mvc:content>
                <m:List xmlns:m="sap.m"></m:List>
              </mvc:content>
            </mvc:View>`);
        });
      });
    });

    context("aggregation tag", () => {
      it("will not detect an issue when the attribute is 'core:require'", () => {
        assertNoIssues(`
          <mvc:View
            xmlns:mvc="sap.ui.core.mvc"
            xmlns:core="sap.ui.core">
            <mvc:content core:require="">
            </mvc:content>
          </mvc:View>`);
      });

      it("will not detect an issue when the attribute is 'sap.ui.dt:designtime'", () => {
        assertNoIssues(`
          <mvc:View
            xmlns:mvc="sap.ui.core.mvc"
            xmlns:dt="sap.ui.dt">
            <mvc:content dt:designtime=""></mvc:content>
          </mvc:View>`);
      });

      it("will not detect an issue when the attribute is 'template:require'", () => {
        assertNoIssues(`
          <mvc:View
            xmlns:mvc="sap.ui.core.mvc"
            xmlns:template="http://schemas.sap.com/sapui5/extension/sap.ui.core.template/1">
            <mvc:content template:require=""></mvc:content>
          </mvc:View>`);
      });

      it("will not detect an issue when the attribute namespace is custom data", () => {
        assertNoIssues(`
          <mvc:View
            xmlns:mvc="sap.ui.core.mvc"
            xmlns:custom="http://schemas.sap.com/sapui5/extension/sap.ui.core.CustomData/1">
            <mvc:content custom:unknownattr=""></mvc:content>
          </mvc:View>`);
      });

      it("will not detect an issue when the attribute is xmlns (default)", () => {
        assertNoIssues(`
          <mvc:View
            xmlns:mvc="sap.ui.core.mvc"">
            <mvc:content xmlns="sap.m">
            </mvc:content>
          </mvc:View>`);
      });

      it("will not detect an issue when the attribute is xmlns (with name)", () => {
        assertNoIssues(`
          <mvc:View
            xmlns:mvc="sap.ui.core.mvc"">
            <mvc:content xmlns:m="sap.m">
            </mvc:content>
          </mvc:View>`);
      });
    });

    context("unknown tag", () => {
      it("will not detect an issue when the attribute name is unknown for tag starting with lowecase", () => {
        assertNoIssues(`
          <mvc:View
            xmlns:mvc="sap.ui.core.mvc"
            xmlns="sap.m">
            <mvc:content_TYPO TYPO="">
            </mvc:content_TYPO>
          </mvc:View>`);
      });

      it("will not detect an issue when the attribute name is unknown for tag starting with uppercase", () => {
        assertNoIssues(`
          <mvc:View
            xmlns:mvc="sap.ui.core.mvc">
            <mvc:content>
              <List_TYPO TYPO=""></List_TYPO>
            </mvc:content>
          </mvc:View>`);
      });

      it("will not detect an issue when the attribute name is unknown for tag in known namespace", () => {
        assertNoIssues(`
          <mvc:View_TYPO
            xmlns:mvc="sap.ui.core.mvc"
            xmlns="sap.m"
            busy_TYPO="true">
          </mvc:View_TYPO>`);
      });
    });

    context("non-reproducible unit tests", () => {
      it("will not detect an issue when the attribute doesn't have a key", () => {
        const xmlSnippet = `
            <mvc:View
              xmlns:mvc="sap.ui.core.mvc"
              attr="">
            </mvc:View>`;

        const { cst, tokenVector } = parse(xmlSnippet);
        const ast = buildAst(cst as DocumentCstNode, tokenVector);
        const attr = ast.rootElement?.attributes[0];
        expectExists(attr, "attr");
        const attrWithoutKey = {
          ...attr,
          key: null,
        };
        const issues = validators.validateUnknownAttributeKey(
          attrWithoutKey,
          ui5SemanticModel
        );
        expect(issues).to.be.empty;
      });
    });
  });
});
Example #15
Source File: use-of-depracated-attribute-spec.ts    From ui5-language-assistant with Apache License 2.0 4 votes vote down vote up
describe("the use of deprecated attribute validation", () => {
  let ui5SemanticModel: UI5SemanticModel;

  before(async () => {
    ui5SemanticModel = await generateModel({
      version: "1.74.0",
      modelGenerator: generate,
    });
  });

  context("true positive scenarios", () => {
    function assertSingleIssue(
      xmlSnippet: string,
      message: string,
      issueKind: string
    ) {
      return assertSingleIssueBase(
        ui5SemanticModel,
        {
          attribute: [validators.validateUseOfDeprecatedAttribute],
        },
        issueKind,
        "warn",
        xmlSnippet,
        message
      );
    }

    it("will detect usage of a deprecated attribute property", () => {
      const pageClass = ui5SemanticModel.classes["sap.m.Page"];
      const navButtonTextProperty = find(
        pageClass.properties,
        (_) => _.name === "navButtonText"
      );

      assertSingleIssue(
        `<mvc:View xmlns:m="sap.m" 
          xmlns:mvc="sap.ui.core.mvc">
          <m:Page ?navButtonText?="">
          </m:Page>
        </mvc:View>`,
        buildDeprecatedIssueMessage({
          symbol: navButtonTextProperty as DeprecatedUI5Symbol,
          model: ui5SemanticModel,
        }),
        "UseOfDeprecatedProperty"
      );
    });

    it("will detect usage of a deprecated attribute event", () => {
      const appClass = ui5SemanticModel.classes["sap.m.App"];
      const orientationChangeEvent = find(
        appClass.events,
        (_) => _.name === "orientationChange"
      );

      assertSingleIssue(
        `<mvc:View xmlns:m="sap.m" 
          xmlns:mvc="sap.ui.core.mvc">
          <m:App ?orientationChange?="">
          </m:App>
        </mvc:View>`,
        buildDeprecatedIssueMessage({
          symbol: orientationChangeEvent as DeprecatedUI5Symbol,
          model: ui5SemanticModel,
        }),
        "UseOfDeprecatedEvent"
      );
    });

    it("will detect usage of a deprecated attribute association", () => {
      const popoverClass = ui5SemanticModel.classes["sap.m.Popover"];
      const leftButtonAssociation = find(
        popoverClass.associations,
        (_) => _.name === "leftButton"
      );

      assertSingleIssue(
        `<mvc:View xmlns:m="sap.m" 
          xmlns:mvc="sap.ui.core.mvc">
          <m:Popover ?leftButton?="">
          </m:Popover>
        </mvc:View>`,
        buildDeprecatedIssueMessage({
          symbol: leftButtonAssociation as DeprecatedUI5Symbol,
          model: ui5SemanticModel,
        }),
        "UseOfDeprecatedAssociation"
      );
    });

    it("will detect usage of a deprecated attribute aggregation", () => {
      const genericTileClass = ui5SemanticModel.classes["sap.m.GenericTile"];
      const iconAggregation = find(
        genericTileClass.aggregations,
        (_) => _.name === "icon"
      );

      assertSingleIssue(
        `<mvc:View xmlns:m="sap.m" 
          xmlns:mvc="sap.ui.core.mvc">
          <m:GenericTile ?icon?="">
          </m:GenericTile> 
        </mvc:View>`,
        buildDeprecatedIssueMessage({
          symbol: iconAggregation as DeprecatedUI5Symbol,
          model: ui5SemanticModel,
        }),
        "UseOfDeprecatedAggregation"
      );
    });
  });

  context("negative edge cases", () => {
    let assertNoIssues: (xmlSnippet: string) => void;
    before(() => {
      assertNoIssues = partial(assertNoIssuesBase, ui5SemanticModel, {
        attribute: [validators.validateUseOfDeprecatedAttribute],
      });
    });

    it("will not detect an issue when the attribute key has not been deprecated", () => {
      assertNoIssues(
        `<mvc:View xmlns:m="sap.m" 
          xmlns:mvc="sap.ui.core.mvc" busy="true">
        </mvc:View`
      );
    });

    it("will not detect an issue when the enclosing tag is not a UI5 class", () => {
      assertNoIssues(
        `<mvc:View1
          xmlns:mvc="sap.ui.core.mvc"
          xmlns="sap.m"
          busy="true">
        </mvc:View1>`
      );
    });

    it("will not detect an issue when the attribute is part of a UI5 Class tag but not a recognized property", () => {
      assertNoIssues(
        `<mvc:View
          xmlns:mvc="sap.ui.core.mvc"
          xmlns="sap.m"
          busy1="untrue">
        </mvc:View>`
      );
    });
  });

  context("non-reproducible unit tests", () => {
    it("will not detect an issue when the attribute doesn't have a key", () => {
      const xmlSnippet = `
          <mvc:View
            xmlns:mvc="sap.ui.core.mvc"
            attr="">
          </mvc:View>`;

      const { cst, tokenVector } = parse(xmlSnippet);
      const ast = buildAst(cst as DocumentCstNode, tokenVector);
      const attr = ast.rootElement?.attributes[0];
      expectExists(attr, "attr");
      const attrWithoutKey = {
        ...attr,
        key: null,
      };

      const issues = validators.validateUseOfDeprecatedAttribute(
        attrWithoutKey,
        ui5SemanticModel
      );

      expect(issues).to.be.empty;
    });
  });
});
Example #16
Source File: cardinality-of-aggregation-spec.ts    From ui5-language-assistant with Apache License 2.0 4 votes vote down vote up
describe("the cardinality aggregation validation", () => {
  let ui5SemanticModel: UI5SemanticModel;

  before(async () => {
    ui5SemanticModel = await generateModel({
      version: "1.74.0",
      modelGenerator: generate,
    });
  });

  context("true positive scenarios", () => {
    let assertSingleIssue: (xmlSnippet: string, message: string) => void;
    before(() => {
      assertSingleIssue = partial(
        assertSingleIssueBase,
        ui5SemanticModel,
        {
          element: [validators.validateExplicitAggregationCardinality],
        },
        "InvalidAggregationCardinality",
        "error"
      );
    });

    it("will detect aggregation with cardinality of 0..1 with more than one element", () => {
      assertSingleIssue(
        `<mvc:View xmlns:uxap="sap.uxap" xmlns:m="sap.m"
            xmlns:mvc="sap.ui.core.mvc"
            xmlns="sap.ui.commons">
            <m:Panel>
              <m:headerToolbar>
                <m:Toolbar></m:Toolbar>
                <?m:Toolbar?></m:Toolbar>
              </m:headerToolbar>
            </m:Panel>
          </mvc:View>`,
        buildMessage(INVALID_AGGREGATION_CARDINALITY.msg, "headerToolbar")
      );
    });

    it("multi tags with single aggreation - will detect aggregation with more elements than its cardinality allows", () => {
      assertSingleIssue(
        `<mvc:View xmlns:uxap="sap.uxap" xmlns:m="sap.m"
            xmlns:mvc="sap.ui.core.mvc"
            xmlns="sap.ui.commons">
            <m:Panel>
              <m:headerToolbar>
                <m:Toolbar></m:Toolbar>
              </m:headerToolbar>
              <m:headerToolbar>
                <?m:Toolbar?></m:Toolbar>
              </m:headerToolbar>
            </m:Panel>
          </mvc:View>`,
        buildMessage(INVALID_AGGREGATION_CARDINALITY.msg, "headerToolbar")
      );
    });

    it("will detect aggregation with cardinality of 0..1 with more than one element - element without name", () => {
      assertSingleIssue(
        `<mvc:View xmlns:uxap="sap.uxap" xmlns:m="sap.m"
            xmlns:mvc="sap.ui.core.mvc"
            xmlns="sap.ui.commons">
            <m:Panel>
              <m:headerToolbar>
                <m:Toolbar></m:Toolbar>
              </m:headerToolbar>
              <m:headerToolbar>
              ?<></>?
              </m:headerToolbar>
            </m:Panel>
          </mvc:View>`,
        buildMessage(INVALID_AGGREGATION_CARDINALITY.msg, "headerToolbar")
      );
    });
  });

  context("negative edge cases", () => {
    let assertNoIssues: (xmlSnippet: string) => void;
    before(() => {
      assertNoIssues = partial(assertNoIssuesBase, ui5SemanticModel, {
        element: [validators.validateExplicitAggregationCardinality],
      });
    });

    it("will not detect an issue when there is an aggregation with only one element", () => {
      assertNoIssues(
        `<mvc:View xmlns:uxap="sap.uxap" xmlns:m="sap.m"
            xmlns:mvc="sap.ui.core.mvc"
            xmlns="sap.ui.commons">
            <m:Panel>
              <m:headerToolbar>
                <m:Toolbar></m:Toolbar>
              </m:headerToolbar>
            </m:Panel>
          </mvc:View>`
      );
    });

    it("will not detect an issue when there is an aggregation with cardinality of 0..n", () => {
      assertNoIssues(
        `<mvc:View xmlns:uxap="sap.uxap" xmlns:m="sap.m"
            xmlns:mvc="sap.ui.core.mvc"
            xmlns="sap.ui.commons">
            <m:Panel>
              <content>
                <m:Toolbar></m:Toolbar>
                <m:Toolbar></m:Toolbar>
              </content>
            </m:Panel>
          </mvc:View>`
      );
    });
  });
});
Example #17
Source File: non-stable-id-spec.ts    From ui5-language-assistant with Apache License 2.0 4 votes vote down vote up
describe("the use of non stable id validation", () => {
  let ui5SemanticModel: UI5SemanticModel;

  before(async () => {
    ui5SemanticModel = await generateModel({
      version: "1.74.0",
      modelGenerator: generate,
    });
  });

  context("true positive scenarios", () => {
    let assertSingleIssue: (xmlSnippet: string, message: string) => void;
    before(() => {
      assertSingleIssue = partial(
        assertSingleIssueBase,
        ui5SemanticModel,
        {
          element: [validators.validateNonStableId],
        },
        "NonStableIDIssue",
        "error"
      );
    });

    it("will detect missing stable id in non-whitelisted UI5 class", () => {
      assertSingleIssue(
        `<mvc:View xmlns:uxap="sap.uxap" xmlns:m="sap.m"
          xmlns:mvc="sap.ui.core.mvc"
          xmlns="sap.ui.commons">
            <?m:Panel?>
            </m:Panel>
        </mvc:View>`,
        buildMessage(NON_STABLE_ID.msg, "Panel")
      );
    });

    it("will detect missing stable id in custom control", () => {
      assertSingleIssue(
        `<mvc:View xmlns:uxap="sap.uxap"
          xmlns:mvc="sap.ui.core.mvc"
          xmlns="sap.ui.commons" xmlns:custom="sap.m">
            <?custom:Button?>
            </custom:Button>
        </mvc:View>`,
        buildMessage(NON_STABLE_ID.msg, "Button")
      );
    });

    it("will detect missing stable id in root level custom control", () => {
      assertSingleIssue(
        `<?custom:View?
          xmlns:custom="foo.bar"
          xmlns="bar.foo">
            <Button id="dummy-id">
            </Button>
        </custom:View>`,
        buildMessage(NON_STABLE_ID.msg, "View")
      );
    });

    it("will detect missing stable id in whitelisted root class when it's not in the root", () => {
      assertSingleIssue(
        `<mvc:View xmlns:uxap="sap.uxap" xmlns:m="sap.m"
            xmlns:mvc="sap.ui.core.mvc"
            xmlns="sap.ui.commons">
              <?mvc:View?>
              </mvc:View>
          </mvc:View>`,
        buildMessage(NON_STABLE_ID.msg, "View")
      );
    });

    it("will detect missing stable in sub element when the parent element has attribute sap.ui.dt:designtime='not-adaptable'", () => {
      assertSingleIssue(
        `<mvc:View xmlns:uxap="sap.uxap" xmlns:m="sap.m"
          xmlns:mvc="sap.ui.core.mvc"
          xmlns="sap.ui.commons"
          xmlns:sap.ui.dt="sap.ui.dt">
            <m:Panel sap.ui.dt:designtime="not-adaptable">
              <?m:Button?></m:Button>
            </m:Panel>
        </mvc:View>`,
        buildMessage(NON_STABLE_ID.msg, "Button")
      );
    });

    it("will detect missing stable id when there is null id attribute value", () => {
      assertSingleIssue(
        `<mvc:View xmlns:uxap="sap.uxap" xmlns:m="sap.m"
          xmlns:mvc="sap.ui.core.mvc"
          xmlns="sap.ui.commons">
            <?m:Panel? id=>
            </m:Panel>
        </mvc:View>`,
        buildMessage(NON_STABLE_ID.msg, "Panel")
      );
    });

    it("will detect missing stable id when there is empty id attribute value", () => {
      assertSingleIssue(
        `<mvc:View xmlns:uxap="sap.uxap" xmlns:m="sap.m"
          xmlns:mvc="sap.ui.core.mvc"
          xmlns="sap.ui.commons">
            <?m:Panel? id="">
            </m:Panel>
        </mvc:View>`,
        buildMessage(NON_STABLE_ID.msg, "Panel")
      );
    });
  });

  context("negative edge cases", () => {
    let assertNoIssues: (xmlSnippet: string) => void;
    before(() => {
      assertNoIssues = partial(assertNoIssuesBase, ui5SemanticModel, {
        element: [validators.validateNonStableId],
      });
    });

    it("will not detect an issue for a root-whitelisted UI5 class", () => {
      assertNoIssues(
        `<!-- sap.ui.core.mvc.View is whitlisted root class -->
        <mvc:View xmlns:uxap="sap.uxap" xmlns:m="sap.m"
          xmlns:mvc="sap.ui.core.mvc"
          xmlns="sap.ui.commons">
        </mvc:View>`
      );
    });

    it("will not detect an issue for a root-whitelisted UI5 class - core ns", () => {
      assertNoIssues(
        `<!-- sap.ui.core.FragmentDefinition is whitlisted root class -->
        <core:FragmentDefinition xmlns="sap.m" xmlns:core="sap.ui.core">
        </core:FragmentDefinition>`
      );
    });

    it("will not detect an issue for a whitelisted UI5 class", () => {
      assertNoIssues(
        `<mvc:View xmlns:core="sap.ui.core" xmlns:uxap="sap.uxap" xmlns:m="sap.m"
          xmlns:mvc="sap.ui.core.mvc"
          xmlns="sap.ui.commons">
            <m:Button id="yyy">
                <m:customData>
                    <core:CustomData></core:CustomData>
                </m:customData>
            </m:Button>
        </mvc:View>`
      );
    });

    it("will not detect an issue for a control with attribute sap.ui.dt:designtime='not-adaptable'", () => {
      assertNoIssues(
        `<mvc:View xmlns:uxap="sap.uxap" xmlns:m="sap.m"
            xmlns:mvc="sap.ui.core.mvc"
            xmlns="sap.ui.commons"
            xmlns:sap.ui.dt="sap.ui.dt">
              <m:Panel sap.ui.dt:designtime="not-adaptable">
              </m:Panel>
        </mvc:View>`
      );
    });

    it("will not detect an issue for a control and it's sub elements when it contains attribute sap.ui.dt:designtime='not-adaptable-tree'", () => {
      assertNoIssues(
        `<mvc:View xmlns:uxap="sap.uxap" xmlns:m="sap.m"
          xmlns:mvc="sap.ui.core.mvc"
          xmlns="sap.ui.commons"
          xmlns:sap.ui.dt="sap.ui.dt">
            <m:Panel sap.ui.dt:designtime="not-adaptable-tree">
                <m:Button>
                </m:Button>
            </m:Panel>
        </mvc:View>`
      );
    });

    it("will not detect an issue for tag without a name", () => {
      assertNoIssues(
        `< >
        </View>`
      );
    });
  });
});
Example #18
Source File: type-of-aggregation-spec.ts    From ui5-language-assistant with Apache License 2.0 4 votes vote down vote up
describe("the type aggregation validation", () => {
  let ui5SemanticModel: UI5SemanticModel;

  before(async () => {
    ui5SemanticModel = await generateModel({
      version: "1.74.0",
      modelGenerator: generate,
    });
  });

  context("true positive scenarios", () => {
    let assertSingleIssue: (xmlSnippet: string, message: string) => void;
    before(() => {
      assertSingleIssue = partial(
        assertSingleIssueBase,
        ui5SemanticModel,
        {
          element: [validators.validateAggregationType],
        },
        "InvalidAggregationType",
        "error"
      );
    });

    it("will detect mismatch of class to explicit aggregation of 'UI5Class' type", () => {
      assertSingleIssue(
        `<mvc:View xmlns:uxap="sap.uxap" xmlns:m="sap.m"
            xmlns:mvc="sap.ui.core.mvc"
            xmlns="sap.ui.commons">
            <m:Panel>
              <m:headerToolbar>
                <?Button?></Button>
              </m:headerToolbar>
            </m:Panel>
         </mvc:View>`,
        buildMessage(
          INVALID_AGGREGATION_TYPE.msg,
          "Button",
          "headerToolbar",
          "Toolbar"
        )
      );
    });

    it("will detect mismatch of class to default aggregation of 'UI5Interface' type", () => {
      assertSingleIssue(
        `<mvc:View xmlns:uxap="sap.uxap" xmlns:m="sap.m"
              xmlns:mvc="sap.ui.core.mvc"
              xmlns="sap.ui.commons">
              <m:Panel>
                <?ToolbarSeparator?></ToolbarSeparator>
              </m:Panel>
         </mvc:View>`,
        buildMessage(
          INVALID_AGGREGATION_TYPE.msg,
          "ToolbarSeparator",
          "content",
          "Control"
        )
      );
    });

    it("will detect mismatch of class to explicit aggregation of 'UI5Class' type", () => {
      assertSingleIssue(
        `<mvc:View xmlns:uxap="sap.uxap" xmlns:m="sap.m"
              xmlns:mvc="sap.ui.core.mvc"
              xmlns="sap.ui.commons">
              <m:Page>
                <m:footer>
                  <!-- The class "Toolbar" is under the aggregation "footer" and must match the type "IBar" -->
                  <?Toolbar?></Toolbar>
                </m:footer>
              </m:Page>
        </mvc:View>`,
        buildMessage(INVALID_AGGREGATION_TYPE.msg, "Toolbar", "footer", "IBar")
      );
    });
  });

  context("negative edge cases", () => {
    let assertNoIssues: (xmlSnippet: string) => void;
    before(() => {
      assertNoIssues = partial(assertNoIssuesBase, ui5SemanticModel, {
        element: [validators.validateAggregationType],
      });
    });

    it("will not detect an issue when the class is under the default aggregation and matching its type", () => {
      assertNoIssues(
        `<mvc:View xmlns:uxap="sap.uxap" xmlns:m="sap.m"
          xmlns:mvc="sap.ui.core.mvc"
          xmlns="sap.ui.commons">
          <m:Shell></m:Shell>
        </mvc:View>`
      );
    });

    it("will not detect an issue when the class is under non-ui5 aggregation", () => {
      assertNoIssues(
        `<mvc:View xmlns:uxap="sap.uxap" xmlns:m="sap.m"
        xmlns:mvc="sap.ui.core.mvc"
        xmlns="sap.ui.commons">
        <UnknownTag>
          <Toolbar></Toolbar>
        </UnknownTag>
      </mvc:View>`
      );
    });

    it("will not detect an issue when the class is under explicit aggregation when the aggregartion type is not a UI5Class or UI5Interface", () => {
      const clonedModel = cloneDeep(ui5SemanticModel);
      const viewClass = clonedModel.classes["sap.ui.core.mvc.View"];
      const contentAggregation = find(
        viewClass.aggregations,
        (_) => _.name === "content"
      ) as UI5Aggregation;
      expect(contentAggregation).to.exist;
      contentAggregation.type = undefined;
      viewClass.aggregations = [contentAggregation];
      const xmlSnippet = `
      <mvc:View
        xmlns:mvc="sap.ui.core.mvc"
        xmlns="sap.m">
        <mvc:content>
          <Shell></Shell>
        </mvc:content>
      </mvc:View>`;

      assertNoIssuesBase(
        clonedModel,
        {
          element: [validators.validateAggregationType],
        },
        xmlSnippet
      );
    });

    it("will not detect an issue when the class is a `sap.ui.core.Fragment", () => {
      assertNoIssues(
        `<mvc:View xmlns:uxap="sap.uxap" 
        xmlns:m="sap.m"
        xmlns:mvc="sap.ui.core.mvc"
        xmlns:core="sap.ui.core">
        <m:Page>
            <m:content>
                <core:Fragment fragmentName="Fragment1" type="XML" />
            </m:content>
        </m:Page>
      </mvc:View>`
      );
    });
  });
});
Example #19
Source File: unknown-tag-name-spec.ts    From ui5-language-assistant with Apache License 2.0 4 votes vote down vote up
describe("the unknown tag name validation", () => {
  let ui5SemanticModel: UI5SemanticModel;

  before(async () => {
    ui5SemanticModel = await generateModel({
      version: "1.74.0",
      modelGenerator: generate,
    });
  });

  context("true positive scenarios", () => {
    let assertSingleIssue: (xmlSnippet: string, message: string) => void;
    before(() => {
      assertSingleIssue = partial(
        assertSingleIssueBase,
        ui5SemanticModel,
        {
          element: [validators.validateUnknownTagName],
        },
        "UnknownTagName",
        "error"
      );
    });

    context("tag with namespace", () => {
      it("will detect an invalid class name in root tag", () => {
        assertSingleIssue(
          `<?mvc:View_TYPO?
            xmlns:mvc="sap.ui.core.mvc"
            xmlns="sap.m">
          </mvc:View_TYPO>`,
          buildMessage(UNKNOWN_CLASS_IN_NS.msg, "View_TYPO", "sap.ui.core.mvc")
        );
      });

      it("will detect an invalid class name under class that has default aggregation", () => {
        assertSingleIssue(
          `<mvc:View
            xmlns:mvc="sap.ui.core.mvc"
            xmlns:m="sap.m">
            <?m:Button_TYPO?>
            </m:Button_TYPO>
          </mvc:View>`,
          buildMessage(UNKNOWN_CLASS_IN_NS.msg, "Button_TYPO", "sap.m")
        );
      });

      it("will detect an invalid class name under class that doesn't have a default aggregation", () => {
        assertSingleIssue(
          `<mvc:View
            xmlns:mvc="sap.ui.core.mvc"
            xmlns:m="sap.m">
            <m:SplitApp>
              <?m:Button_TYPO?>
              </m:Button_TYPO>
            </m:SplitApp>
          </mvc:View>`,
          buildMessage(
            UNKNOWN_TAG_NAME_IN_NS_UNDER_CLASS.msg,
            "Button_TYPO",
            "sap.m",
            "sap.m.SplitApp"
          )
        );
      });

      it("will detect an invalid class name under aggregation", () => {
        assertSingleIssue(
          `<mvc:View
            xmlns:mvc="sap.ui.core.mvc"
            xmlns:m="sap.m">
            <mvc:content>
              <?m:Button_TYPO?>
              </m:Button_TYPO>
            </mvc:content>
          </mvc:View>`,
          buildMessage(UNKNOWN_CLASS_IN_NS.msg, "Button_TYPO", "sap.m")
        );
      });

      it("will detect an invalid aggregation when it's in the wrong namespace", () => {
        assertSingleIssue(
          `<mvc:View
            xmlns:mvc="sap.ui.core.mvc"
            xmlns:m="sap.m">
            <?m:content?>
            </mv:content>
          </mvc:View>`,
          buildMessage(UNKNOWN_CLASS_IN_NS.msg, "content", "sap.m")
        );
      });

      it("will detect an invalid class name under aggregation in the same namespace", () => {
        assertSingleIssue(
          `<mvc:View
            xmlns:mvc="sap.ui.core.mvc">
            <mvc:content>
              <?mvc:Button_TYPO?>
              </mvc:Button_TYPO>
            </mvc:content>
          </mvc:View>`,
          buildMessage(
            UNKNOWN_CLASS_IN_NS.msg,
            "Button_TYPO",
            "sap.ui.core.mvc"
          )
        );
      });

      it("will detect an invalid aggregation name under known class tag without default aggregation", () => {
        assertSingleIssue(
          `<mvc:View
            xmlns:mvc="sap.ui.core.mvc"
            xmlns:m="sap.m">
            <m:SplitApp>
              <?m:content_TYPO?>
              </m:content_TYPO>
            </m:SplitApp>
          </mvc:View>`,
          buildMessage(
            UNKNOWN_TAG_NAME_IN_NS_UNDER_CLASS.msg,
            "content_TYPO",
            "sap.m",
            "sap.m.SplitApp"
          )
        );
      });

      it("will detect an issue for unknown name under unknown class in a known namespace", () => {
        const xmlSnippet = `
          <mvc:View
            xmlns:mvc="sap.ui.core.mvc"
            xmlns:m="sap.m">
            <?m:SplitApp_TYPO?>
              <?m:Button_TYPO?>
              </m:Button_TYPO>
            </m:SplitApp_TYPO>
          </mvc:View>`;
        const expectedRanges = computeExpectedRanges(xmlSnippet);

        testValidationsScenario({
          model: ui5SemanticModel,
          xmlText: xmlSnippet,
          validators: { element: [validators.validateUnknownTagName] },
          assertion: (issues) => {
            expect(issues).to.deep.equalInAnyOrder([
              {
                kind: "UnknownTagName",
                message: buildMessage(
                  UNKNOWN_CLASS_IN_NS.msg,
                  "SplitApp_TYPO",
                  "sap.m"
                ),
                offsetRange: expectedRanges[0],
                severity: "error",
              },
              {
                kind: "UnknownTagName",
                message: buildMessage(
                  UNKNOWN_TAG_NAME_IN_NS.msg,
                  "Button_TYPO",
                  "sap.m"
                ),
                offsetRange: expectedRanges[1],
                severity: "error",
              },
            ]);
          },
        });
      });
    });

    context("tag without namespace", () => {
      context("when default namespace is not defined", () => {
        it("will detect an invalid class name in root tag", () => {
          assertSingleIssue(
            `<?View?>
            </View>`,
            buildMessage(UNKNOWN_CLASS_WITHOUT_NS.msg, "View")
          );
        });

        it("will detect an invalid class name under known aggregation tag", () => {
          assertSingleIssue(
            `<mvc:View
              xmlns:mvc="sap.ui.core.mvc">
              <mvc:content>
                <?List?></List>
              </mvc:content>
            </mvc:View>`,
            buildMessage(UNKNOWN_CLASS_WITHOUT_NS.msg, "List")
          );
        });

        it("will detect an invalid class or aggregation name under known class tag with default aggregation", () => {
          assertSingleIssue(
            `<mvc:View
              xmlns:mvc="sap.ui.core.mvc">
              <?List?></List>
            </mvc:View>`,
            buildMessage(
              UNKNOWN_TAG_NAME_IN_CLASS.msg,
              "List",
              "sap.ui.core.mvc.View"
            )
          );
        });

        it("will detect an invalid aggregation namespace under known class tag without default aggregation", () => {
          assertSingleIssue(
            `<mvc:View
              xmlns:mvc="sap.ui.core.mvc"
              xmlns:m="sap.m">
              <m:SplitApp>
                <?content?>
                </content>
              </m:SplitApp>
            </mvc:View>`,
            buildMessage(
              UNKNOWN_AGGREGATION_IN_CLASS_DIFF_NAMESPACE.msg,
              "content",
              "sap.m.SplitApp"
            )
          );
        });

        it("will detect an issue for unknown name under unknown class in non-default non-ui5 namespace when name starts with uppercase", () => {
          assertSingleIssue(
            `<mvc:View
              xmlns:mvc="sap.ui.core.mvc"
              xmlns:typo="sap.m_TYPO">
              <typo:SplitApp>
                <?Button_TYPO?>
                </Button_TYPO>
              </typo:SplitApp>
            </mvc:View>`,
            buildMessage(UNKNOWN_TAG_NAME_NO_NS.msg, "Button_TYPO")
          );
        });
      });

      context("when default namespace is a ui5 namespace", () => {
        it("will detect an issue for unknown name under unknown class in the default namespace", () => {
          const xmlSnippet = `
            <mvc:View
              xmlns:mvc="sap.ui.core.mvc"
              xmlns="sap.m">
              <?SplitApp_TYPO?>
                <?Button_TYPO?>
                </Button_TYPO>
              </SplitApp_TYPO>
            </mvc:View>`;
          const expectedRanges = computeExpectedRanges(xmlSnippet);

          testValidationsScenario({
            model: ui5SemanticModel,
            xmlText: xmlSnippet,
            validators: { element: [validators.validateUnknownTagName] },
            assertion: (issues) => {
              expect(issues).to.deep.equalInAnyOrder([
                {
                  kind: "UnknownTagName",
                  message: buildMessage(
                    UNKNOWN_TAG_NAME_IN_NS_UNDER_CLASS.msg,
                    "SplitApp_TYPO",
                    "sap.m",
                    "sap.ui.core.mvc.View"
                  ),
                  offsetRange: expectedRanges[0],
                  severity: "error",
                },
                {
                  kind: "UnknownTagName",
                  message: buildMessage(
                    UNKNOWN_TAG_NAME_IN_NS.msg,
                    "Button_TYPO",
                    "sap.m"
                  ),
                  offsetRange: expectedRanges[1],
                  severity: "error",
                },
              ]);
            },
          });
        });
      });
    });

    context("when default namespace is a ui5 namespace", () => {
      it("will detect an invalid class name in root tag", () => {
        assertSingleIssue(
          `<?View_TYPO?
            xmlns="sap.ui.core.mvc">
          </View_TYPO>`,
          buildMessage(UNKNOWN_CLASS_IN_NS.msg, "View_TYPO", "sap.ui.core.mvc")
        );
      });

      it("will detect an invalid class name under known aggregation tag", () => {
        assertSingleIssue(
          `<View
            xmlns="sap.ui.core.mvc">
            <content>
              <?List_TYPO?></List_TYPO>
            </content>
          </View>`,
          buildMessage(UNKNOWN_CLASS_IN_NS.msg, "List_TYPO", "sap.ui.core.mvc")
        );
      });

      it("will detect an invalid class or aggregation name under known class tag with default aggregation", () => {
        assertSingleIssue(
          `<View
            xmlns="sap.ui.core.mvc">
            <?List_TYPO?></List_TYPO>
          </View>`,
          buildMessage(
            UNKNOWN_TAG_NAME_IN_NS_UNDER_CLASS.msg,
            "List_TYPO",
            "sap.ui.core.mvc",
            "sap.ui.core.mvc.View"
          )
        );
      });

      it("will detect an invalid aggregation name under known class tag without default aggregation", () => {
        assertSingleIssue(
          `<mvc:View
            xmlns:mvc="sap.ui.core.mvc"
            xmlns="sap.m">
            <SplitApp>
              <?content_TYPO?>
              </content_TYPO>
            </SplitApp>
          </mvc:View>`,
          buildMessage(
            UNKNOWN_AGGREGATION_IN_CLASS.msg,
            "content_TYPO",
            "sap.m.SplitApp"
          )
        );
      });
    });
  });

  context("negative edge cases", () => {
    let assertNoIssues: (xmlSnippet: string) => void;
    before(() => {
      assertNoIssues = partial(assertNoIssuesBase, ui5SemanticModel, {
        element: [validators.validateUnknownTagName],
      });
    });

    context("tag with namespace", () => {
      context("non-ui5 namespace", () => {
        it("will not detect an issue when namespace is unknown", () => {
          assertNoIssues(
            `<mvc:View_TYPO
              xmlns:mvc="sap.ui.core.mvc_TYPO"
              xmlns="sap.m">
            </mvc:View_TYPO>`
          );
        });

        it("will not detect an issue when namespace is xhtml", () => {
          assertNoIssues(
            `<mvc:View_TYPO
              xmlns:mvc="http://www.w3.org/1999/xhtml"
              xmlns="sap.m">
            </mvc:View_TYPO>`
          );
        });

        it("will not detect an issue when namespace is not defined in xmlns attribute", () => {
          assertNoIssues(
            `<mvc:View_TYPO
              xmlns="sap.m">
            </mvc:View_TYPO>`
          );
        });
      });

      context("ui5 namespace", () => {
        let assertSingleIssue: (xmlSnippet: string, message: string) => void;
        before(() => {
          assertSingleIssue = partial(
            assertSingleIssueBase,
            ui5SemanticModel,
            {
              element: [validators.validateUnknownTagName],
            },
            "UnknownTagName",
            "error"
          );
        });
        it("will not detect an issue for known class in the root tag", () => {
          assertNoIssues(
            `<mvc:View
              xmlns:mvc="sap.ui.core.mvc"
              xmlns="sap.m">
            </mvc:View>`
          );
        });

        it("will not detect an issue for sap.ui.core.FragmentDefinition in the root tag", () => {
          assertNoIssues(
            `<core:FragmentDefinition xmlns="sap.m" xmlns:core="sap.ui.core">
                <Label text="These controls are within one multi-root Fragment:" />
                <Input />
                <Button text="Still in the same Fragment" />
            </core:FragmentDefinition>`
          );
        });

        it("will not detect an issue for known aggregation in a different namespace prefix that references the same namespace", () => {
          assertNoIssues(
            `<mvc:View
              xmlns:mvc="sap.ui.core.mvc"
              xmlns:mvc2="sap.ui.core.mvc">
              <mvc2:content>
              </mvc2:content>
            </mvc:View>`
          );
        });

        it("will not detect an issue for known class under class that has default aggregation", () => {
          assertNoIssues(
            `<mvc:View
              xmlns:mvc="sap.ui.core.mvc"
              xmlns:m="sap.m">
              <m:Button>
              </m:Button>
            </mvc:View>`
          );
        });

        it("will not detect an issue for known class under class that doesn't have a default aggregation", () => {
          assertNoIssues(
            `<mvc:View
              xmlns:mvc="sap.ui.core.mvc"
              xmlns:m="sap.m">
              <m:SplitApp>
                <m:Button>
                </m:Button>
              </m:SplitApp>
            </mvc:View>`
          );
        });

        it("will not detect an issue for known class under aggregation", () => {
          assertNoIssues(
            `<mvc:View
              xmlns:mvc="sap.ui.core.mvc"
              xmlns:m="sap.m">
              <mvc:content>
                <m:Button>
                </m:Button>
              </mvc:content>
            </mvc:View>`
          );
        });

        it("will not detect an issue for known class under tag in unknown namespace", () => {
          assertNoIssues(
            `<mvc:View
              xmlns:mvc="sap.ui.core.mvc"
              xmlns:m="sap.m"
              xmlns:customns="customns">
              <customns:SplitApp>
                <m:Button>
                </m:Button>
              </customns:SplitApp>
            </mvc:View>`
          );
        });

        it("will not detect an issue for known class under tag in unknown default namespace", () => {
          assertNoIssues(
            `<mvc:View
              xmlns:mvc="sap.ui.core.mvc"
              xmlns:m="sap.m"
              xmlns="customns">
              <SplitApp>
                <m:Button>
                </m:Button>
              </SplitApp>
            </mvc:View>`
          );
        });

        it("will not detect an issue for sap.ui.core.ExtensionPoint as top level element in sap.ui.core.mvc.View", () => {
          assertNoIssues(
            `<mvc:View xmlns:mvc="sap.ui.core.mvc" xmlns:core="sap.ui.core">
                <core:ExtensionPoint name="extension1"/>
            </mvc:View>`
          );
        });

        it("will not detect an issue for sap.ui.core.ExtensionPoint as top level element in sap.ui.core.Fragment", () => {
          assertNoIssues(
            `<FragmentDefinition xmlns="sap.ui.core">
                <ExtensionPoint name="extension1"/>
            </FragmentDefinition>`
          );
        });

        it("will not detect an issue for sap.ui.core.ExtensionPoint as nested element in sap.ui.core.mvc.View", () => {
          assertNoIssues(
            `<mvc:View xmlns:mvc="sap.ui.core.mvc" xmlns:core="sap.ui.core" xmlns:m="sap.m">
                <m:Page>
                  <m:content>
                    <core:ExtensionPoint name="extension1"/>
                  </m:content>
                </m:Page>
            </mvc:View>`
          );
        });

        it("will not detect an issue for sap.ui.core.ExtensionPoint as nested element in sap.ui.core.Fragment", () => {
          assertNoIssues(
            `<FragmentDefinition xmlns="sap.ui.core">
              <m:Panel>
                <m:content>
                  <core:ExtensionPoint name="extension1"/>
                </m:content>
              </m:Panel>
            </FragmentDefinition>`
          );
        });

        it("will detect an issue for sap.ui.core.ExtensionPoint in the root tag", () => {
          assertSingleIssue(
            `<?ExtensionPoint? name="extension1"></ExtensionPoint>`,
            buildMessage(UNKNOWN_CLASS_WITHOUT_NS.msg, "ExtensionPoint")
          );
        });
      });
    });

    context("tag without namespace", () => {
      context("when default namespace is a ui5 namespace", () => {
        it("will not detect an issue for known class in the root tag", () => {
          assertNoIssues(
            `<View
              xmlns="sap.ui.core.mvc">
            </View>`
          );
        });

        it("will not detect an issue for sap.ui.core.FragmentDefinition in the root tag", () => {
          assertNoIssues(
            `<FragmentDefinition xmlns:m="sap.m" xmlns="sap.ui.core">
                <m:Label text="These controls are within one multi-root Fragment:" />
                <m:Input />
                <m:Button text="Still in the same Fragment" />
            </FragmentDefinition>`
          );
        });

        it("will not detect an issue for known class under known aggregation tag", () => {
          assertNoIssues(
            `<mvc:View
              xmlns:mvc="sap.ui.core.mvc"
              xmlns="sap.m">
              <mvc:content>
                <Button>
                </Button>
              </mvc:content>
            </mvc:View>`
          );
        });

        it("will not detect an issue for known class under known class tag with default aggregation", () => {
          assertNoIssues(
            `<mvc:View
              xmlns:mvc="sap.ui.core.mvc"
              xmlns="sap.m">
              <Button>
              </Button>
            </mvc:View>`
          );
        });

        it("will not detect an issue for known class under known class tag without default aggregation", () => {
          // This should be detected in a different validation
          assertNoIssues(
            `<mvc:View
              xmlns:mvc="sap.ui.core.mvc"
              xmlns="sap.m">
              <SplitApp>
                <Button>
                </Button>
              </SplitApp>
            </mvc:View>`
          );
        });

        it("will not detect an issue for known aggregation under known class tag with default aggregation", () => {
          assertNoIssues(
            `<mvc:View
              xmlns:mvc="sap.ui.core.mvc"
              xmlns="sap.m">
              <mvc:content>
              </mvc:content>
            </mvc:View>`
          );
        });

        it("will not detect an issue for known aggregation under known class tag without default aggregation", () => {
          assertNoIssues(
            `<mvc:View
              xmlns:mvc="sap.ui.core.mvc"
              xmlns="sap.m">
              <SplitApp>
                <masterPages>
                </masterPages>
              </SplitApp>
            </mvc:View>`
          );
        });

        it("will not detect an issue for known class under tag in unknown namespace", () => {
          assertNoIssues(
            `<mvc:View
              xmlns:mvc="sap.ui.core.mvc_TYPO"
              xmlns="sap.m">
              <SplitApp>
              </SplitApp>
            </mvc:View>`
          );
        });

        it("will not detect an issue for unknown name under unknown class in non-ui5 namespace", () => {
          assertNoIssues(
            `<mvc:View
              xmlns:mvc="sap.ui.core.mvc"
              xmlns:typo="sap.m_TYPO"
              xmlns="sap.m">
              <typo:SplitApp>
                <typo:content_TYPO>
                </typo:content_TYPO>
              </typo:SplitApp>
            </mvc:View>`
          );
        });
      });

      context("when default namespace is a non-ui5 namespace", () => {
        it("will not detect an issue for unknown name in root tag", () => {
          assertNoIssues(
            `<View_TYPO
              xmlns="sap.ui.core.mvc_TYPO">
            </View_TYPO>`
          );
        });

        it("will not detect an issue for unknown name under known aggregation tag", () => {
          assertNoIssues(
            `<mvc:View
              xmlns:mvc="sap.ui.core.mvc"
              xmlns="sap.m_TYPO">
              <mvc:content>
                <Button_TYPO>
                </Button_TYPO>
              </mvc:content>
            </mvc:View>`
          );
        });

        it("will not detect an issue for unknown name under known class tag with default aggregation", () => {
          assertNoIssues(
            `<mvc:View
              xmlns:mvc="sap.ui.core.mvc"
              xmlns="sap.m_TYPO">
              <Button_TYPO>
              </Button_TYPO>
            </mvc:View>`
          );
        });

        it("will not detect an issue for unknown name under known class tag without default aggregation", () => {
          // The tag might still be allowed if it's not a class, e.g. template tags are allowed everywhere
          assertNoIssues(
            `<mvc:View
              xmlns:mvc="sap.ui.core.mvc"
              xmlns:m="sap.m"
              xmlns="sap.m_TYPO">
              <m:SplitApp>
                <Button_TYPO>
                </Button_TYPO>
              </m:SplitApp>
            </mvc:View>`
          );
        });

        it("will not detect an issue for unknown name under unknown class in default non-ui5 namespace when name starts with lowercase", () => {
          assertNoIssues(
            `<mvc:View
              xmlns:mvc="sap.ui.core.mvc"
              xmlns="sap.m_TYPO">
              <SplitApp>
                <content_TYPO>
                </content_TYPO>
              </SplitApp>
            </mvc:View>`
          );
        });

        it("will not detect an issue for unknown name under unknown class in default non-ui5 namespace when name starts with uppercase", () => {
          assertNoIssues(
            `<mvc:View
              xmlns:mvc="sap.ui.core.mvc"
              xmlns="sap.m_TYPO">
              <SplitApp>
                <Button_TYPO>
                </Button_TYPO>
              </SplitApp>
            </mvc:View>`
          );
        });
      });

      context("when default namespace is not defined", () => {
        it("will not detect an issue for tag without a name", () => {
          assertNoIssues(
            `< >
            </View>`
          );
        });

        it("will not detect an issue for unknown name under unknown class in non-default non-ui5 namespace when name starts with lowercase", () => {
          assertNoIssues(
            `<mvc:View
              xmlns:mvc="sap.ui.core.mvc"
              xmlns:typo="sap.m_TYPO">
              <typo:SplitApp>
                <typo:content_TYPO>
                </typo:content_TYPO>
              </typo:SplitApp>
            </mvc:View>`
          );
        });
      });
    });
  });
});
Example #20
Source File: use-of-deprecated-aggregation-spec.ts    From ui5-language-assistant with Apache License 2.0 4 votes vote down vote up
describe("the use of deprecated aggregation validation", () => {
  let ui5SemanticModel: UI5SemanticModel;

  before(async () => {
    ui5SemanticModel = await generateModel({
      version: "1.74.0",
      modelGenerator: generate,
    });
  });

  context("true positive scenarios", () => {
    let assertSingleIssue: (xmlSnippet: string, message: string) => void;
    before(() => {
      assertSingleIssue = partial(
        assertSingleIssueBase,
        ui5SemanticModel,
        {
          element: [validators.validateUseOfDeprecatedAggregation],
        },
        "UseOfDeprecatedAggregation",
        "warn"
      );
    });

    it("will detect usage of a deprecated aggregation", () => {
      const bubbleChart =
        ui5SemanticModel.classes["sap.ca.ui.charts.BubbleChart"];
      const contentAggregation = find(
        bubbleChart.aggregations,
        (_) => _.name === "content"
      );

      assertSingleIssue(
        `<mvc:View xmlns:mvc="sap.ui.core.mvc" xmlns:charts="sap.ca.ui.charts">
          <mvc:content>
            <charts:BubbleChart>
                <?charts:content?>
                </charts:content>
            </charts:BubbleChart>
          </mvc:content>
        </m:View>`,
        buildDeprecatedIssueMessage({
          symbol: contentAggregation as DeprecatedUI5Symbol,
          model: ui5SemanticModel,
        })
      );
    });

    it("will detect usage of a deprecated aggregation with self closing syntax", () => {
      const bubbleChart =
        ui5SemanticModel.classes["sap.ca.ui.charts.BubbleChart"];
      const contentAggregation = find(
        bubbleChart.aggregations,
        (_) => _.name === "content"
      );

      assertSingleIssue(
        `<mvc:View xmlns:mvc="sap.ui.core.mvc" xmlns:charts="sap.ca.ui.charts">
          <mvc:content>
            <charts:BubbleChart>
                <?charts:content?/>
            </charts:BubbleChart>
          </mvc:content>
        </m:View>`,
        buildDeprecatedIssueMessage({
          symbol: contentAggregation as DeprecatedUI5Symbol,
          model: ui5SemanticModel,
        })
      );
    });

    it("will detect usage of a deprecated aggregation in an unclosed element to enable **early warning** to users", () => {
      const bubbleChart =
        ui5SemanticModel.classes["sap.ca.ui.charts.BubbleChart"];
      const contentAggregation = find(
        bubbleChart.aggregations,
        (_) => _.name === "content"
      );

      assertSingleIssue(
        `<mvc:View xmlns:mvc="sap.ui.core.mvc" xmlns:charts="sap.ca.ui.charts">
          <mvc:content>
            <charts:BubbleChart>
              <?charts:content?
            </charts:BubbleChart>
          </mvc:content>
        </m:View>`,
        buildDeprecatedIssueMessage({
          symbol: contentAggregation as DeprecatedUI5Symbol,
          model: ui5SemanticModel,
        })
      );
    });
  });

  context("negative edge cases", () => {
    let assertNoIssues: (xmlSnippet: string) => void;
    before(() => {
      assertNoIssues = partial(assertNoIssuesBase, ui5SemanticModel, {
        element: [validators.validateUseOfDeprecatedAggregation],
      });
    });

    it("will not detect an issue when the aggregation has not been deprecated", () => {
      assertNoIssues(
        `<mvc:View xmlns:m="sap.m" xmlns:mvc="sap.ui.core.mvc" xmlns:charts="sap.ca.ui.charts">
          <mvc:content>
            <m:Bar>
              <!-- unlike sap.ca.ui.charts.BubbleChart.content, sap.ui.core.TooltipBase is not deprecated -->
              <m:tooltip></m:tooltip>
            </m:Bar>
          </mvc:content>
        </m:View>`
      );
    });
  });
});
Example #21
Source File: ColumnComponent.tsx    From next-basics with GNU General Public License v3.0 4 votes vote down vote up
export function ColumnComponent(
  props: ColumnComponentProps
): React.ReactElement {
  const { column, field, rowIndex, hasLabel, formValue } = props;
  const { label, name } = column;
  const { name: fieldName, ...restField } = field;

  const rowValue = formValue?.[rowIndex];

  const labelNode = useMemo(
    () => hasLabel && rowIndex === 0 && <div>{label}</div>,
    [label, rowIndex, hasLabel]
  );

  const disabled = useMemo(
    () => getRealValue(column.props?.disabled, [rowValue, rowIndex]),
    [column.props?.disabled, rowValue, rowIndex]
  );

  const rules = useMemo(
    () =>
      column.rules?.map((rule) => {
        if (typeof rule.validator === "function") {
          return {
            message: rule.message,
            validator: partial(rule.validator, _, _, _, {
              formValue,
              rowValue,
              rowIndex,
            }),
          };
        }
        if (rule.unique) {
          return {
            validator: (rule: any, value: any, cb: any) => {
              if (!isNil(value) && value !== "") {
                const valueList = formValue?.map((row) => row[name]);
                const matchList = valueList?.filter(
                  (v, i) => isEqual(v, value) && i !== rowIndex
                );
                matchList?.length && cb(rule.message);
              }
              cb();
            },
            message: rule.message,
          };
        }
        return rule;
      }),
    [column.rules, formValue, name, rowIndex, rowValue]
  );

  switch (column.type) {
    case "input": {
      const { placeholder, type, maxLength, allowClear } = column.props || {};

      return (
        <Form.Item
          {...restField}
          label={labelNode}
          name={[fieldName, name]}
          rules={rules}
        >
          <Input
            style={{ width: "100%" }}
            placeholder={placeholder}
            disabled={disabled}
            type={type}
            maxLength={maxLength}
            allowClear={allowClear}
          />
        </Form.Item>
      );
    }
    case "inputNumber": {
      const { placeholder, min, max, step, precision } = column.props || {};

      return (
        <Form.Item
          {...restField}
          label={labelNode}
          name={[fieldName, name]}
          rules={rules}
        >
          <InputNumber
            style={{ width: "100%" }}
            placeholder={placeholder}
            min={min}
            max={max}
            step={step}
            precision={precision}
            disabled={disabled}
          />
        </Form.Item>
      );
    }
    case "inputPassword": {
      const { placeholder, visibilityToggle } = column.props || {};

      return (
        <Form.Item
          {...restField}
          label={labelNode}
          name={[fieldName, name]}
          rules={rules}
        >
          <Input.Password
            style={{ width: "100%" }}
            placeholder={placeholder}
            disabled={disabled}
            visibilityToggle={visibilityToggle}
          />
        </Form.Item>
      );
    }
    case "select": {
      const {
        placeholder,
        allowClear,
        mode,
        options = [],
        showSearch,
        groupBy,
        tokenSeparators,
        maxTagCount,
        popoverPositionType,
      } = column.props || {};
      const searchProps = showSearch
        ? {
            showSearch: true,
            filterOption: (input: string, option: any) => {
              return option.label
                ?.toLowerCase()
                .includes(input.trim().toLowerCase());
            },
          }
        : {
            showSearch: false,
          };

      return (
        <Form.Item
          {...restField}
          label={labelNode}
          name={[fieldName, name]}
          rules={rules}
        >
          <Select
            style={{ width: "100%" }}
            placeholder={placeholder}
            disabled={disabled}
            allowClear={allowClear}
            mode={mode}
            tokenSeparators={tokenSeparators}
            maxTagCount={maxTagCount}
            {...(popoverPositionType === "parent"
              ? {
                  getPopupContainer: (triggerNode) => triggerNode.parentElement,
                }
              : {})}
            {...searchProps}
          >
            {groupBy ? getOptsGroups(options, groupBy) : getOptions(options)}
          </Select>
        </Form.Item>
      );
    }
    case "cascader": {
      const {
        placeholder,
        allowClear,
        options,
        expandTrigger,
        popupPlacement,
        showSearch,
        fieldNames,
      } = column.props || {};

      return (
        <Form.Item
          {...restField}
          label={labelNode}
          name={[fieldName, name]}
          rules={rules}
        >
          <Cascader
            style={{ width: "100%" }}
            placeholder={placeholder}
            allowClear={allowClear}
            disabled={disabled}
            expandTrigger={expandTrigger}
            popupPlacement={popupPlacement}
            options={options}
            showSearch={showSearch}
            fieldNames={fieldNames}
          />
        </Form.Item>
      );
    }
    default: {
      return null;
    }
  }
}